OTEscrowTranslation.m   [plain text]

/*
* Copyright (c) 2020 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, 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 <Foundation/Foundation.h>
#import "OTEscrowTranslation.h"

#import <SoftLinking/SoftLinking.h>
#import <CloudServices/SecureBackup.h>
#import <CloudServices/SecureBackupConstants.h>
#import "keychain/ot/categories/OctagonEscrowRecoverer.h"
#import <OctagonTrust/OTEscrowRecordMetadata.h>
#import <OctagonTrust/OTEscrowRecordMetadataClientMetadata.h>
#import <Security/OTConstants.h>
#import "keychain/ot/OTClique+Private.h"
#import <utilities/debugging.h>

SOFT_LINK_OPTIONAL_FRAMEWORK(PrivateFrameworks, CloudServices);

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wstrict-prototypes"

SOFT_LINK_CLASS(CloudServices, SecureBackup);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupErrorDomain, NSErrorDomain);

/* Escrow Authentication Information used for SRP*/
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupAuthenticationAppleID, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupAuthenticationPassword, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupAuthenticationiCloudEnvironment, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupAuthenticationAuthToken, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupAuthenticationEscrowProxyURL, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupIDMSRecoveryKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupFMiPRecoveryKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupFMiPUUIDKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupAuthenticationDSID, NSString*);

/* CDP recovery information */
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupUseCachedPassphraseKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupPassphraseKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupRecoveryKeyKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupContainsiCDPDataKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupSilentRecoveryAttemptKey, NSString*);

/* Escrow Record Fields set by SecureBackup*/
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupIsEnabledKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupUsesRecoveryKeyKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupLastBackupTimestampKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupLastBackupDateKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupEscrowTrustStatusKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupRecordStatusKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupRecordIDKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupPeerInfoDataKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupPeerInfoSerialNumberKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupPeerInfoOSVersionKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupAlliCDPRecordsKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupRecordLabelKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupEscrowedSPKIKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupBottleIDKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupSerialNumberKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupBuildVersionKey, NSString*);

SOFT_LINK_CONSTANT(CloudServices, kSecureBackupUsesRandomPassphraseKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupUsesComplexPassphraseKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupUsesNumericPassphraseKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupNumericPassphraseLengthKey, NSString*);

SOFT_LINK_CONSTANT(CloudServices, kSecureBackupRecoveryRequiresVerificationTokenKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupAccountIsHighSecurityKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupSMSTargetInfoKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupMetadataKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupUsesMultipleiCSCKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupClientMetadataKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupBottleValidityKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupEscrowDateKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupRemainingAttemptsKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupCoolOffEndKey, NSString*);
SOFT_LINK_CONSTANT(CloudServices, kSecureBackupRecoveryStatusKey, NSString*);

#pragma clang diagnostic pop

static NSString * const kCliqueSecureBackupTimestampKey = @"com.apple.securebackup.timestamp";
static NSString * const kCliqueEscrowServiceRecordMetadataKey = @"metadata";
static NSString * const kCliqueSecureBackupEncodedMetadataKey = @"encodedMetadata";
static NSString * const kCliqueSecureBackupKeybagDigestKey = @"BackupKeybagDigest";
static NSString * const kCliqueSecureBackupMetadataTimestampKey = @"SecureBackupMetadataTimestamp";
static NSString * const kCliqueSecureBackupDeviceColor = @"device_color";
static NSString * const kCliqueSecureBackupDeviceEnclosureColor = @"device_enclosure_color";
static NSString * const kCliqueSecureBackupDeviceMID = @"device_mid";
static NSString * const kCliqueSecureBackupDeviceModel = @"device_model";
static NSString * const kCliqueSecureBackupDeviceModelClass = @"device_model_class";
static NSString * const kCliqueSecureBackupDeviceModelVersion = @"device_model_version";
static NSString * const kCliqueSecureBackupDeviceName = @"device_name";
static NSString * const kCliqueSecureBackupDevicePlatform = @"device_platform";
static NSString * const kCliqueSecureBackupSilentAttemptAllowed = @"silentAttemptAllowed";

@implementation OTEscrowTranslation

//dictionary to escrow auth
+ (OTEscrowAuthenticationInformation*) dictionaryToEscrowAuthenticationInfo:(NSDictionary*)dictionary
{
if ([OTClique isCloudServicesAvailable] == NO) {
return nil;
}

OTEscrowAuthenticationInformation* escrowAuthInfo = [[OTEscrowAuthenticationInformation alloc] init];
escrowAuthInfo.authenticationAppleid = dictionary[getkSecureBackupAuthenticationAppleID()];
escrowAuthInfo.authenticationAuthToken = dictionary[getkSecureBackupAuthenticationAuthToken()];
escrowAuthInfo.authenticationDsid = dictionary[getkSecureBackupAuthenticationDSID()];
escrowAuthInfo.authenticationEscrowproxyUrl = dictionary[getkSecureBackupAuthenticationEscrowProxyURL()];
escrowAuthInfo.authenticationIcloudEnvironment = dictionary[getkSecureBackupAuthenticationiCloudEnvironment()];
escrowAuthInfo.authenticationPassword = dictionary[getkSecureBackupAuthenticationPassword()];
escrowAuthInfo.fmipUuid = dictionary[getkSecureBackupFMiPUUIDKey()];
escrowAuthInfo.fmipRecovery = [dictionary[getkSecureBackupFMiPRecoveryKey()] boolValue];
escrowAuthInfo.idmsRecovery = [dictionary[getkSecureBackupIDMSRecoveryKey()] boolValue];

return escrowAuthInfo;
}

//escrow auth to dictionary
+ (NSDictionary*) escrowAuthenticationInfoToDictionary:(OTEscrowAuthenticationInformation*)escrowAuthInfo
{
if ([OTClique isCloudServicesAvailable] == NO) {
return nil;
}

NSMutableDictionary* dictionary = [NSMutableDictionary dictionary];
if(![escrowAuthInfo.authenticationAppleid isEqualToString:@""]){
dictionary[getkSecureBackupAuthenticationAppleID()] = escrowAuthInfo.authenticationAppleid;
}
if(![escrowAuthInfo.authenticationAuthToken isEqualToString:@""]){
dictionary[getkSecureBackupAuthenticationAuthToken()] = escrowAuthInfo.authenticationAuthToken;
}
if(![escrowAuthInfo.authenticationDsid isEqualToString:@""]){
dictionary[getkSecureBackupAuthenticationDSID()] = escrowAuthInfo.authenticationDsid;
}
if(![escrowAuthInfo.authenticationEscrowproxyUrl isEqualToString:@""]){
dictionary[getkSecureBackupAuthenticationEscrowProxyURL()] = escrowAuthInfo.authenticationEscrowproxyUrl;
}
if(![escrowAuthInfo.authenticationIcloudEnvironment isEqualToString:@""]){
dictionary[getkSecureBackupAuthenticationiCloudEnvironment()] = escrowAuthInfo.authenticationIcloudEnvironment;
}
if(![escrowAuthInfo.authenticationPassword isEqualToString:@""]){
dictionary[getkSecureBackupAuthenticationPassword()] = escrowAuthInfo.authenticationPassword;
}
if(![escrowAuthInfo.fmipUuid isEqualToString:@""]){
dictionary[getkSecureBackupFMiPUUIDKey()] = escrowAuthInfo.fmipUuid;
}
dictionary[getkSecureBackupFMiPRecoveryKey()] = escrowAuthInfo.fmipRecovery ? @YES : @NO;
dictionary[getkSecureBackupIDMSRecoveryKey()] = escrowAuthInfo.idmsRecovery ? @YES : @NO;

return dictionary;
}

+ (OTCDPRecoveryInformation*)dictionaryToCDPRecoveryInformation:(NSDictionary*)dictionary
{
if ([OTClique isCloudServicesAvailable] == NO) {
return nil;
}

OTCDPRecoveryInformation* info = [[OTCDPRecoveryInformation alloc] init];
info.recoverySecret = dictionary[getkSecureBackupPassphraseKey()];
info.useCachedSecret = [dictionary[getkSecureBackupUseCachedPassphraseKey()] boolValue];
info.recoveryKey = dictionary[getkSecureBackupRecoveryKeyKey()];
info.usePreviouslyCachedRecoveryKey = [dictionary[getkSecureBackupUsesRecoveryKeyKey()] boolValue];
info.silentRecoveryAttempt = [dictionary[@"SecureBackupSilentRecoveryAttempt"] boolValue];
info.containsIcdpData =[dictionary[getkSecureBackupContainsiCDPDataKey()] boolValue];
info.usesMultipleIcsc = [dictionary[getkSecureBackupUsesMultipleiCSCKey()] boolValue];
return info;
}

+ (NSDictionary*)cdpRecoveryInformationToDictionary:(OTCDPRecoveryInformation*)info
{
if ([OTClique isCloudServicesAvailable] == NO) {
return nil;
}

NSMutableDictionary* dictionary = [NSMutableDictionary dictionary];
dictionary[getkSecureBackupPassphraseKey()] = info.recoverySecret;
dictionary[getkSecureBackupUseCachedPassphraseKey()] = info.useCachedSecret ? @YES : @NO;
dictionary[getkSecureBackupRecoveryKeyKey()] = info.recoveryKey;
dictionary[getkSecureBackupUsesRecoveryKeyKey()] = info.usePreviouslyCachedRecoveryKey ? @YES : @NO;
dictionary[@"SecureBackupSilentRecoveryAttempt"] = info.silentRecoveryAttempt ? @YES : @NO;
dictionary[getkSecureBackupContainsiCDPDataKey()] = info.containsIcdpData ? @YES : @NO;
dictionary[getkSecureBackupUsesMultipleiCSCKey()] = info.usesMultipleIcsc ? @YES : @NO;

return dictionary;
}

+ (NSDate *)_dateWithSecureBackupDateString:(NSString *)dateString
{
NSDateFormatter *dateFormatter = [NSDateFormatter new];
dateFormatter.dateFormat = @"dd-MM-yyyy HH:mm:ss";
NSDate *ret = [dateFormatter dateFromString:dateString];

if (ret) {
return ret;
}
// New date format is GMT
dateFormatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
dateFormatter.dateFormat = @"yyyy-MM-dd HH:mm:ss";
return [dateFormatter dateFromString:dateString];
}

+ (NSString*)_stringWithSecureBackupDate:(NSDate*) date
{
NSDateFormatter *dateFormatter = [NSDateFormatter new];
dateFormatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
dateFormatter.dateFormat = @"yyyy-MM-dd HH:mm:ss";
return [dateFormatter stringFromDate: date];
}

+ (OTEscrowRecordMetadata *) dictionaryToMetadata:(NSDictionary*)dictionary
{
if ([OTClique isCloudServicesAvailable] == NO) {
return nil;
}

OTEscrowRecordMetadata *metadata = [[OTEscrowRecordMetadata alloc] init];

metadata.backupKeybagDigest = dictionary[kCliqueSecureBackupKeybagDigestKey];
metadata.secureBackupUsesMultipleIcscs = [dictionary[getkSecureBackupUsesMultipleiCSCKey()] boolValue];
metadata.bottleId = dictionary[getkSecureBackupBottleIDKey()];
metadata.bottleValidity = dictionary[@"bottleValid"];
NSDate* secureBackupTimestamp = [OTEscrowTranslation _dateWithSecureBackupDateString: dictionary[kCliqueSecureBackupTimestampKey]];

metadata.secureBackupTimestamp = [secureBackupTimestamp timeIntervalSince1970];
metadata.escrowedSpki = dictionary[getkSecureBackupEscrowedSPKIKey()];
metadata.peerInfo = dictionary[getkSecureBackupPeerInfoDataKey()];
metadata.serial = dictionary[getkSecureBackupSerialNumberKey()];

NSDictionary* escrowInformationMetadataClientMetadata = dictionary[getkSecureBackupClientMetadataKey()];
metadata.clientMetadata = [[OTEscrowRecordMetadataClientMetadata alloc] init];
NSNumber *platform = escrowInformationMetadataClientMetadata[kCliqueSecureBackupDevicePlatform];
metadata.clientMetadata.devicePlatform = [platform longLongValue];

NSDate* secureBackupMetadataTimestamp = [OTEscrowTranslation _dateWithSecureBackupDateString: escrowInformationMetadataClientMetadata[kCliqueSecureBackupMetadataTimestampKey]];
metadata.clientMetadata.secureBackupMetadataTimestamp = [secureBackupMetadataTimestamp timeIntervalSince1970];

NSNumber *passphraseLength = escrowInformationMetadataClientMetadata[getkSecureBackupNumericPassphraseLengthKey()];
metadata.clientMetadata.secureBackupNumericPassphraseLength = [passphraseLength longLongValue];
metadata.clientMetadata.secureBackupUsesComplexPassphrase = [escrowInformationMetadataClientMetadata[getkSecureBackupUsesComplexPassphraseKey()] boolValue];
metadata.clientMetadata.secureBackupUsesNumericPassphrase = [escrowInformationMetadataClientMetadata[getkSecureBackupUsesNumericPassphraseKey()] boolValue];
metadata.clientMetadata.deviceColor = escrowInformationMetadataClientMetadata[kCliqueSecureBackupDeviceColor];
metadata.clientMetadata.deviceEnclosureColor = escrowInformationMetadataClientMetadata[kCliqueSecureBackupDeviceEnclosureColor];
metadata.clientMetadata.deviceMid = escrowInformationMetadataClientMetadata[kCliqueSecureBackupDeviceMID];
metadata.clientMetadata.deviceModel = escrowInformationMetadataClientMetadata[kCliqueSecureBackupDeviceModel];
metadata.clientMetadata.deviceModelClass = escrowInformationMetadataClientMetadata[kCliqueSecureBackupDeviceModelClass];
metadata.clientMetadata.deviceModelVersion = escrowInformationMetadataClientMetadata[kCliqueSecureBackupDeviceModelVersion];
metadata.clientMetadata.deviceName = escrowInformationMetadataClientMetadata[kCliqueSecureBackupDeviceName];

return metadata;
}

//dictionary to escrow record
+ (OTEscrowRecord*) dictionaryToEscrowRecord:(NSDictionary*)dictionary
{
if ([OTClique isCloudServicesAvailable] == NO) {
return nil;
}

OTEscrowRecord* record = [[OTEscrowRecord alloc] init];
NSDate* creationDate = dictionary[getkSecureBackupEscrowDateKey()];
record.creationDate = [creationDate timeIntervalSince1970];
NSDictionary* escrowInformationMetadata = dictionary[kCliqueEscrowServiceRecordMetadataKey];
record.escrowInformationMetadata = [OTEscrowTranslation dictionaryToMetadata:escrowInformationMetadata];

NSNumber *remainingAttempts = dictionary[getkSecureBackupRemainingAttemptsKey()];

record.remainingAttempts = [remainingAttempts longLongValue];
record.label = dictionary[getkSecureBackupRecordLabelKey()];
record.recordStatus = [dictionary[getkSecureBackupRecordStatusKey()] isEqualToString:@"valid"] ? OTEscrowRecord_RecordStatus_RECORD_STATUS_VALID : OTEscrowRecord_RecordStatus_RECORD_STATUS_INVALID;
record.silentAttemptAllowed = [dictionary[kCliqueSecureBackupSilentAttemptAllowed] boolValue];
record.recordId = dictionary[getkSecureBackupRecordIDKey()];
record.serialNumber = dictionary[getkSecureBackupPeerInfoSerialNumberKey()];
if(dictionary[getkSecureBackupCoolOffEndKey()]) {
record.coolOffEnd = [dictionary[getkSecureBackupCoolOffEndKey()] longLongValue];
}
record.recoveryStatus = [dictionary[getkSecureBackupRecoveryStatusKey()] intValue];
return record;
}

+ (NSDictionary *) metadataToDictionary:(OTEscrowRecordMetadata*)metadata
{
if ([OTClique isCloudServicesAvailable] == NO) {
return nil;
}

NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
dictionary[getkSecureBackupClientMetadataKey()] = [NSMutableDictionary dictionary];

dictionary[kCliqueSecureBackupKeybagDigestKey] = metadata.backupKeybagDigest;
dictionary[getkSecureBackupUsesMultipleiCSCKey()] = [[NSNumber alloc]initWithUnsignedLongLong:metadata.secureBackupUsesMultipleIcscs];
dictionary[getkSecureBackupBottleIDKey()] = metadata.bottleId;
dictionary[@"bottleValid"] = metadata.bottleValidity;
dictionary[kCliqueSecureBackupTimestampKey] = [OTEscrowTranslation _stringWithSecureBackupDate: [NSDate dateWithTimeIntervalSince1970: metadata.secureBackupTimestamp]];
dictionary[getkSecureBackupEscrowedSPKIKey()] = metadata.escrowedSpki;
dictionary[getkSecureBackupPeerInfoDataKey()] = metadata.peerInfo;
dictionary[getkSecureBackupSerialNumberKey()] = metadata.serial;
dictionary[getkSecureBackupClientMetadataKey()][kCliqueSecureBackupDevicePlatform] = [[NSNumber alloc]initWithUnsignedLongLong: metadata.clientMetadata.devicePlatform];
dictionary[getkSecureBackupClientMetadataKey()][kCliqueSecureBackupMetadataTimestampKey] = [OTEscrowTranslation _stringWithSecureBackupDate: [NSDate dateWithTimeIntervalSince1970: metadata.clientMetadata.secureBackupMetadataTimestamp]];
dictionary[getkSecureBackupClientMetadataKey()][getkSecureBackupNumericPassphraseLengthKey()] = [[NSNumber alloc]initWithUnsignedLongLong: metadata.clientMetadata.secureBackupNumericPassphraseLength];
dictionary[getkSecureBackupClientMetadataKey()][getkSecureBackupUsesComplexPassphraseKey()] = [[NSNumber alloc]initWithUnsignedLongLong: metadata.clientMetadata.secureBackupUsesComplexPassphrase];
dictionary[getkSecureBackupClientMetadataKey()][getkSecureBackupUsesNumericPassphraseKey()] = [[NSNumber alloc]initWithUnsignedLongLong: metadata.clientMetadata.secureBackupUsesNumericPassphrase];
dictionary[getkSecureBackupClientMetadataKey()][kCliqueSecureBackupDeviceColor] = metadata.clientMetadata.deviceColor;
dictionary[getkSecureBackupClientMetadataKey()][kCliqueSecureBackupDeviceEnclosureColor] = metadata.clientMetadata.deviceEnclosureColor;
dictionary[getkSecureBackupClientMetadataKey()][kCliqueSecureBackupDeviceMID] = metadata.clientMetadata.deviceMid;
dictionary[getkSecureBackupClientMetadataKey()][kCliqueSecureBackupDeviceModel] = metadata.clientMetadata.deviceModel;
dictionary[getkSecureBackupClientMetadataKey()][kCliqueSecureBackupDeviceModelClass] = metadata.clientMetadata.deviceModelClass;
dictionary[getkSecureBackupClientMetadataKey()][kCliqueSecureBackupDeviceModelVersion] = metadata.clientMetadata.deviceModelVersion;
dictionary[getkSecureBackupClientMetadataKey()][kCliqueSecureBackupDeviceName] = metadata.clientMetadata.deviceName;

return dictionary;
}

//escrow record to dictionary
+ (NSDictionary*) escrowRecordToDictionary:(OTEscrowRecord*)escrowRecord
{
if ([OTClique isCloudServicesAvailable] == NO) {
return nil;
}

NSMutableDictionary* dictionary = [NSMutableDictionary dictionary];
dictionary[getkSecureBackupEscrowDateKey()] = [NSDate dateWithTimeIntervalSince1970: escrowRecord.creationDate];

dictionary[kCliqueEscrowServiceRecordMetadataKey] = [OTEscrowTranslation metadataToDictionary: escrowRecord.escrowInformationMetadata];

dictionary[getkSecureBackupRemainingAttemptsKey()] = [[NSNumber alloc]initWithUnsignedLongLong:escrowRecord.remainingAttempts];
dictionary[getkSecureBackupRecordLabelKey()] = escrowRecord.label;
dictionary[getkSecureBackupRecordStatusKey()] = escrowRecord.recordStatus == OTEscrowRecord_RecordStatus_RECORD_STATUS_VALID ? @"valid" : @"invalid";
dictionary[kCliqueSecureBackupSilentAttemptAllowed] = [[NSNumber alloc] initWithUnsignedLongLong: escrowRecord.silentAttemptAllowed];
dictionary[getkSecureBackupRecordIDKey()] = escrowRecord.recordId;
dictionary[getkSecureBackupPeerInfoSerialNumberKey()] = escrowRecord.serialNumber;
dictionary[getkSecureBackupCoolOffEndKey()] = @(escrowRecord.coolOffEnd);
dictionary[getkSecureBackupRecoveryStatusKey()] = @(escrowRecord.recoveryStatus);

return dictionary;
}

+ (OTICDPRecordContext*)dictionaryToCDPRecordContext:(NSDictionary*)dictionary
{
if ([OTClique isCloudServicesAvailable] == NO) {
return nil;
}

OTICDPRecordContext* context = [[OTICDPRecordContext alloc] init];
context.authInfo = [OTEscrowTranslation dictionaryToEscrowAuthenticationInfo:dictionary];
context.cdpInfo = [OTEscrowTranslation dictionaryToCDPRecoveryInformation:dictionary];

return context;
}

+ (NSDictionary*)CDPRecordContextToDictionary:(OTICDPRecordContext*)context
{
if ([OTClique isCloudServicesAvailable] == NO) {
return nil;
}

NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];

[dictionary addEntriesFromDictionary:[OTEscrowTranslation escrowAuthenticationInfoToDictionary:context.authInfo]];
[dictionary addEntriesFromDictionary:[OTEscrowTranslation cdpRecoveryInformationToDictionary:context.cdpInfo]];

return dictionary;
}

+ (BOOL)supportedRestorePath:(OTICDPRecordContext *)cdpContext
{
return (cdpContext.authInfo.idmsRecovery == false
&& (cdpContext.authInfo.fmipUuid == nil || [cdpContext.authInfo.fmipUuid isEqualToString:@""])
&& cdpContext.authInfo.fmipRecovery == false
&& (cdpContext.cdpInfo.recoveryKey == nil || [cdpContext.cdpInfo.recoveryKey isEqualToString:@""])
&& cdpContext.cdpInfo.usePreviouslyCachedRecoveryKey == false);
}

@end