append/remove key type as necessary to fix verification syncing

// FREEBIE
pull/1/head
Michael Kirk 8 years ago
parent 2059bb4966
commit e746c6b7ec

@ -4,6 +4,7 @@
#import "OWSVerificationStateSyncMessage.h" #import "OWSVerificationStateSyncMessage.h"
#import "Cryptography.h" #import "Cryptography.h"
#import "OWSIdentityManager.h"
#import "OWSSignalServiceProtos.pb.h" #import "OWSSignalServiceProtos.pb.h"
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@ -50,7 +51,7 @@ NS_ASSUME_NONNULL_BEGIN
identityKey:(NSData *)identityKey identityKey:(NSData *)identityKey
recipientId:(NSString *)recipientId recipientId:(NSString *)recipientId
{ {
OWSAssert(identityKey.length > 0); OWSAssert(identityKey.length == kIdentityKeyLength);
OWSAssert(recipientId.length > 0); OWSAssert(recipientId.length > 0);
OWSAssert(self.tuples); OWSAssert(self.tuples);

@ -17,6 +17,7 @@
#import "TSStorageManager.h" #import "TSStorageManager.h"
#import "TextSecureKitEnv.h" #import "TextSecureKitEnv.h"
#import <25519/Curve25519.h> #import <25519/Curve25519.h>
#import <AxolotlKit/NSData+keyVersionByte.h>
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@ -33,7 +34,13 @@ NSString *const OWSIdentityManager_QueuedVerificationStateSyncMessages =
// Don't trust an identity for sending to unless they've been around for at least this long // Don't trust an identity for sending to unless they've been around for at least this long
const NSTimeInterval kIdentityKeyStoreNonBlockingSecondsThreshold = 5.0; const NSTimeInterval kIdentityKeyStoreNonBlockingSecondsThreshold = 5.0;
const NSUInteger kIdentityKeyLength = 32; // The canonical key includes 32 bytes of identity material plus one byte specifying the key type
const NSUInteger kIdentityKeyLength = 33;
// Cryptographic operations do not use the "type" byte of the identity key, so, for legacy reasons we store just
// the identity material.
// TODO: migrate to storing the full 33 byte representation.
const NSUInteger kStoredIdentityKeyLength = 32;
NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationName_IdentityStateDidChange"; NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationName_IdentityStateDidChange";
@ -133,8 +140,8 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
- (BOOL)saveRemoteIdentity:(NSData *)identityKey recipientId:(NSString *)recipientId - (BOOL)saveRemoteIdentity:(NSData *)identityKey recipientId:(NSString *)recipientId
{ {
OWSAssert(identityKey != nil); OWSAssert(identityKey.length == kStoredIdentityKeyLength);
OWSAssert(recipientId != nil); OWSAssert(recipientId.length > 0);
@synchronized(self) @synchronized(self)
{ {
@ -207,7 +214,7 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
recipientId:(NSString *)recipientId recipientId:(NSString *)recipientId
isUserInitiatedChange:(BOOL)isUserInitiatedChange isUserInitiatedChange:(BOOL)isUserInitiatedChange
{ {
OWSAssert(identityKey.length > 0); OWSAssert(identityKey.length == kStoredIdentityKeyLength);
OWSAssert(recipientId.length > 0); OWSAssert(recipientId.length > 0);
@synchronized(self) @synchronized(self)
@ -236,11 +243,8 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
[recipientIdentity updateWithVerificationState:verificationState]; [recipientIdentity updateWithVerificationState:verificationState];
if (isUserInitiatedChange) { if (isUserInitiatedChange) {
[self enqueueSyncMessageForVerificationState:verificationState
identityKey:identityKey
recipientId:recipientId];
[self saveChangeMessagesForRecipientId:recipientId verificationState:verificationState isLocalChange:YES]; [self saveChangeMessagesForRecipientId:recipientId verificationState:verificationState isLocalChange:YES];
[self enqueueSyncMessageForVerificationStateForRecipientId:recipientId];
} else { } else {
// Cancel any pending verification state sync messages for this recipient. // Cancel any pending verification state sync messages for this recipient.
[self clearSyncMessageForRecipientId:recipientId]; [self clearSyncMessageForRecipientId:recipientId];
@ -314,8 +318,8 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
recipientId:(NSString *)recipientId recipientId:(NSString *)recipientId
direction:(TSMessageDirection)direction direction:(TSMessageDirection)direction
{ {
OWSAssert(identityKey != nil); OWSAssert(identityKey.length == kStoredIdentityKeyLength);
OWSAssert(recipientId != nil); OWSAssert(recipientId.length > 0);
OWSAssert(direction != TSMessageDirectionUnknown); OWSAssert(direction != TSMessageDirectionUnknown);
@synchronized(self) @synchronized(self)
@ -353,7 +357,7 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
- (BOOL)isTrustedKey:(NSData *)identityKey forSendingToIdentity:(nullable OWSRecipientIdentity *)recipientIdentity - (BOOL)isTrustedKey:(NSData *)identityKey forSendingToIdentity:(nullable OWSRecipientIdentity *)recipientIdentity
{ {
OWSAssert(identityKey.length == kIdentityKeyLength); OWSAssert(identityKey.length == kStoredIdentityKeyLength);
@synchronized(self) @synchronized(self)
{ {
@ -362,7 +366,7 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
return YES; return YES;
} }
OWSAssert(recipientIdentity.identityKey.length == kIdentityKeyLength); OWSAssert(recipientIdentity.identityKey.length == kStoredIdentityKeyLength);
if (![recipientIdentity.identityKey isEqualToData:identityKey]) { if (![recipientIdentity.identityKey isEqualToData:identityKey]) {
DDLogWarn(@"%@ key mismatch for recipient: %@", self.tag, recipientIdentity.recipientId); DDLogWarn(@"%@ key mismatch for recipient: %@", self.tag, recipientIdentity.recipientId);
return NO; return NO;
@ -397,7 +401,7 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
- (void)createIdentityChangeInfoMessageForRecipientId:(NSString *)recipientId - (void)createIdentityChangeInfoMessageForRecipientId:(NSString *)recipientId
{ {
OWSAssert(recipientId != nil); OWSAssert(recipientId.length > 0);
NSMutableArray<TSMessage *> *messages = [NSMutableArray new]; NSMutableArray<TSMessage *> *messages = [NSMutableArray new];
@ -420,11 +424,8 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
}]; }];
} }
- (void)enqueueSyncMessageForVerificationState:(OWSVerificationState)verificationState - (void)enqueueSyncMessageForVerificationStateForRecipientId:(NSString *)recipientId
identityKey:(NSData *)identityKey
recipientId:(NSString *)recipientId
{ {
OWSAssert(identityKey.length > 0);
OWSAssert(recipientId.length > 0); OWSAssert(recipientId.length > 0);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@ -453,19 +454,26 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
[recipientIds addObject:recipientId]; [recipientIds addObject:recipientId];
}]; }];
}]; }];
OWSVerificationStateSyncMessage *message = OWSVerificationStateSyncMessage *message = [OWSVerificationStateSyncMessage new];
[OWSVerificationStateSyncMessage new];
for (NSString *recipientId in recipientIds) { for (NSString *recipientId in recipientIds) {
OWSRecipientIdentity *recipientIdentity = [OWSRecipientIdentity fetchObjectWithUniqueID:recipientId]; OWSRecipientIdentity *recipientIdentity = [OWSRecipientIdentity fetchObjectWithUniqueID:recipientId];
if (!recipientIdentity) { if (!recipientIdentity) {
OWSFail(@"Could not load recipient identity for recipientId: %@", recipientId); OWSFail(@"Could not load recipient identity for recipientId: %@", recipientId);
continue; continue;
} }
if (recipientIdentity.recipientId.length < 1 || recipientIdentity.identityKey.length < 1) { if (recipientIdentity.recipientId.length < 1) {
OWSFail(@"Invalid recipient identity for recipientId: %@", recipientId); OWSFail(@"Invalid recipient identity for recipientId: %@", recipientId);
continue; continue;
} }
// Prepend key type for transit.
// TODO we should just be storing the key type so we don't have to juggle re-adding it.
NSData *identityKey = [recipientIdentity.identityKey prependKeyType];
if (identityKey.length != kIdentityKeyLength) {
OWSFail(@"Invalid recipient identitykey for recipientId: %@ key: %@", recipientId, identityKey);
continue;
}
if (recipientIdentity.verificationState == OWSVerificationStateNoLongerVerified) { if (recipientIdentity.verificationState == OWSVerificationStateNoLongerVerified) {
// We don't want to sync "no longer verified" state. Other clients can // We don't want to sync "no longer verified" state. Other clients can
// figure this out from the /profile/ endpoint, and this can cause data // figure this out from the /profile/ endpoint, and this can cause data
@ -476,7 +484,7 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
continue; continue;
} }
[message addVerificationState:recipientIdentity.verificationState [message addVerificationState:recipientIdentity.verificationState
identityKey:recipientIdentity.identityKey identityKey:identityKey
recipientId:recipientId]; recipientId:recipientId];
} }
if (message.recipientIds.count > 0) { if (message.recipientIds.count > 0) {
@ -498,14 +506,25 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
[OWSRecipientIdentity enumerateCollectionObjectsUsingBlock:^(OWSRecipientIdentity *recipientIdentity, BOOL *stop) { [OWSRecipientIdentity enumerateCollectionObjectsUsingBlock:^(OWSRecipientIdentity *recipientIdentity, BOOL *stop) {
OWSAssert(recipientIdentity); OWSAssert(recipientIdentity);
OWSAssert(recipientIdentity.recipientId.length > 0); OWSAssert(recipientIdentity.recipientId.length > 0);
OWSAssert(recipientIdentity.identityKey.length > 0); OWSAssert(recipientIdentity.identityKey.length == kStoredIdentityKeyLength);
if (recipientIdentity.recipientId.length < 1 || recipientIdentity.identityKey.length < 1) { if (recipientIdentity.recipientId.length < 1) {
OWSFail(@"Invalid recipient identity for recipientId: %@", recipientIdentity.recipientId); OWSFail(@"Invalid recipient identity for recipientId: %@", recipientIdentity.recipientId);
return; return;
} }
// Prepend key type for transit.
// TODO we should just be storing the key type so we don't have to juggle re-adding it.
NSData *identityKey = [recipientIdentity.identityKey prependKeyType];
if (identityKey.length != kIdentityKeyLength) {
OWSFail(@"Invalid recipient identitykey for recipientId: %@ key: %@",
recipientIdentity.recipientId,
identityKey);
return;
}
[message addVerificationState:recipientIdentity.verificationState [message addVerificationState:recipientIdentity.verificationState
identityKey:recipientIdentity.identityKey identityKey:identityKey
recipientId:recipientIdentity.recipientId]; recipientId:recipientIdentity.recipientId];
}]; }];
if (message.recipientIds.count > 0) { if (message.recipientIds.count > 0) {
@ -581,11 +600,15 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
OWSFail(@"Verification state sync message missing recipientId."); OWSFail(@"Verification state sync message missing recipientId.");
continue; continue;
} }
NSData *identityKey = verified.identityKey; NSData *rawIdentityKey = verified.identityKey;
if (identityKey.length < 1) { if (rawIdentityKey.length != kIdentityKeyLength) {
OWSFail(@"Verification state sync message missing identityKey: %@", recipientId); OWSFail(@"Verification state sync message for recipient: %@ with malformed identityKey: %@",
recipientId,
rawIdentityKey);
continue; continue;
} }
NSData *identityKey = [rawIdentityKey removeKeyType];
switch (verified.state) { switch (verified.state) {
case OWSSignalServiceProtosSyncMessageVerifiedStateDefault: case OWSSignalServiceProtosSyncMessageVerifiedStateDefault:
[self tryToApplyVerificationStateFromSyncMessage:OWSVerificationStateDefault [self tryToApplyVerificationStateFromSyncMessage:OWSVerificationStateDefault
@ -617,7 +640,8 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
OWSFail(@"Verification state sync message missing recipientId."); OWSFail(@"Verification state sync message missing recipientId.");
return; return;
} }
if (identityKey.length < 1) {
if (identityKey.length != kStoredIdentityKeyLength) {
OWSFail(@"Verification state sync message missing identityKey: %@", recipientId); OWSFail(@"Verification state sync message missing identityKey: %@", recipientId);
return; return;
} }

@ -909,19 +909,22 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
} }
NSData *newIdentityKeyWithVersion = newKeyBundle.identityKey; NSData *newIdentityKeyWithVersion = newKeyBundle.identityKey;
if (![newIdentityKeyWithVersion isKindOfClass:[NSData class]]) { if (![newIdentityKeyWithVersion isKindOfClass:[NSData class]]) {
OWSFail(@"%@ unexpected TSInvalidRecipientKey: %@", self.tag, newIdentityKeyWithVersion); OWSFail(@"%@ unexpected TSInvalidRecipientKey: %@", self.tag, newIdentityKeyWithVersion);
failureHandler(error); failureHandler(error);
return; return;
} }
NSData *newIdentityKey = [newIdentityKeyWithVersion removeKeyType]; // TODO migrate to storing the full 33 byte representation of the identity key.
if (newIdentityKey.length != kIdentityKeyLength) { if (newIdentityKeyWithVersion.length != kIdentityKeyLength) {
OWSFail(@"%@ unexpected key length: %lu", self.tag, (unsigned long)newIdentityKey.length); OWSFail(@"%@ unexpected key length: %lu", self.tag, (unsigned long)newIdentityKeyWithVersion.length);
failureHandler(error); failureHandler(error);
return; return;
} }
NSData *newIdentityKey = [newIdentityKeyWithVersion removeKeyType];
[[OWSIdentityManager sharedManager] saveRemoteIdentity:newIdentityKey recipientId:recipient.recipientId]; [[OWSIdentityManager sharedManager] saveRemoteIdentity:newIdentityKey recipientId:recipient.recipientId];
failureHandler(error); failureHandler(error);

Loading…
Cancel
Save