Ensure keyspec is generated before DB is created

// FREEBIE
pull/1/head
Michael Kirk 8 years ago
parent 6f959ff292
commit 4f8db63fb3

@ -1215,7 +1215,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
thread:message.thread
attempts:OWSMessageSenderRetryAttempts
success:^{
DDLogInfo(@"Succesfully sent sync transcript.");
DDLogInfo(@"Successfully sent sync transcript.");
}
failure:^(NSError *error) {
// FIXME: We don't yet honor the isRetryable flag here, since sendSyncTranscriptForMessage

@ -407,6 +407,11 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void);
OWSAssert(options.pragmaJournalSizeLimit == 0);
OWSAssert(options.pragmaMMapSize == 0);
// Sanity checking elsewhere asserts we should only regenerate key specs when
// there is no existing database, so rather than lazily generate in the cipherKeySpecBlock
// we must ensure the keyspec exists before we create the database.
[self ensureDatabaseKeySpecExists];
OWSDatabase *database = [[OWSDatabase alloc] initWithPath:[self databaseFilePath]
serializer:nil
deserializer:[[self class] logOnFailureDeserializer]
@ -564,20 +569,21 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void);
[SAMKeychain deletePasswordForService:keychainService account:keychainDBLegacyPassphrase];
}
- (NSData *)databaseKeySpec
- (void)ensureDatabaseKeySpecExists
{
NSError *error;
NSData *_Nullable data = [[self class] tryToLoadDatabaseCipherKeySpec:&error];
NSData *_Nullable keySpec = [[self class] tryToLoadDatabaseCipherKeySpec:&error];
if (error) {
if (error || (keySpec.length != kSQLCipherKeySpecLength)) {
// Because we use kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,
// the keychain will be inaccessible after device restart until
// device is unlocked for the first time. If the app receives
// a push notification, we won't be able to access the keychain to
// process that notification, so we should just terminate by throwing
// an uncaught exception.
NSString *errorDescription =
[NSString stringWithFormat:@"CipherKeySpec inaccessible. No unlock since device restart? Error: %@", error];
NSString *errorDescription = [NSString
stringWithFormat:@"CipherKeySpec inaccessible. New install or no unlock since device restart? Error: %@",
error];
if (CurrentAppContext().isMainApp) {
UIApplicationState applicationState = CurrentAppContext().mainApplicationState;
errorDescription =
@ -600,9 +606,8 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void);
// At this point, either this is a new install so there's no existing password to retrieve
// or the keychain has become corrupt. Either way, we want to get back to a
// "known good state" and behave like a new install.
BOOL shouldHaveDatabaseMetadata = [NSFileManager.defaultManager fileExistsAtPath:[self databaseFilePath]];
if (shouldHaveDatabaseMetadata) {
BOOL doesDBExist = [NSFileManager.defaultManager fileExistsAtPath:[self databaseFilePath]];
if (doesDBExist) {
OWSFail(@"%@ Could not load database metadata", self.logTag);
OWSProdCritical([OWSAnalyticsEvents storageErrorCouldNotLoadDatabaseSecondAttempt]);
}
@ -610,11 +615,27 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void);
// Try to reset app by deleting database.
[OWSStorage resetAllStorage];
data = [Randomness generateRandomBytes:(int)kSQLCipherKeySpecLength];
[[self class] storeDatabaseCipherKeySpec:data];
keySpec = [Randomness generateRandomBytes:(int)kSQLCipherKeySpecLength];
[[self class] storeDatabaseCipherKeySpec:keySpec];
}
}
return data;
- (NSData *)databaseKeySpec
{
NSError *error;
NSData *_Nullable keySpec = [[self class] tryToLoadDatabaseCipherKeySpec:&error];
if (error) {
DDLogError(@"%@ failed to fetch databaseKeySpec with error: %@", self.logTag, error);
[self raiseKeySpecInaccessibleExceptionWithErrorDescription:@"CipherKeySpec inaccessible"];
}
if (keySpec.length != kSQLCipherKeySpecLength) {
DDLogError(@"%@ keyspec had length: %lu", self.logTag, (unsigned long)keySpec.length);
[self raiseKeySpecInaccessibleExceptionWithErrorDescription:@"CipherKeySpec invalid"];
}
return keySpec;
}
- (void)raiseKeySpecInaccessibleExceptionWithErrorDescription:(NSString *)errorDescription
@ -667,7 +688,7 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void);
OWSRaiseException(
OWSStorageExceptionName_DatabasePasswordUnwritable, @"Setting keychain value failed with error: %@", error);
} else {
DDLogWarn(@"Succesfully set new keychain value.");
DDLogWarn(@"Successfully set new keychain value.");
}
}

Loading…
Cancel
Save