Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MXCrypto: Restart broken Olm sessions #778

Merged
merged 6 commits into from
Feb 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Improvements:
* MXSession: Add createRoomWithParameters with a MXRoomCreationParameters model class.
* MXRoomCreationParameters: Support the initial_state parameter and allow e2e on room creation (vector-im/riot-ios/issues/2943).
* MXCrypto: Expose devicesForUser.
* MXCrypto: Restart broken Olm sessions ([MSC1719](https://github.com/matrix-org/matrix-doc/pull/1719)) (vector-im/riot-ios/issues/2129).
* MXRoomSummary: Add the trust property to indicate trust in other users and devices in the room (vector-im/riot-ios/issues/2906).
* MXStore: Add a method to get related events for a specific event.

Expand Down
21 changes: 21 additions & 0 deletions MatrixSDK/Crypto/Algorithms/MXEncrypting.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,25 @@
success:(void (^)(NSObject *sessionInfo))success
failure:(void (^)(NSError *error))failure;

/**
Re-shares a session key with devices if the key has already been
sent to them.

@param sessionId The id of the outbound session to share.
@param userId The id of the user who owns the target device.
@param deviceId he id of the target device.
@param senderKey The key of the originating device for the session.

@param success A block object called when the operation succeeds.
@param failure A block object called when the operation fails.

@return a MXHTTPOperation instance.
*/
- (MXHTTPOperation*)reshareKey:(NSString*)sessionId
withUser:(NSString*)userId
andDevice:(NSString*)deviceId
senderKey:(NSString*)senderKey
success:(void (^)(void))success
failure:(void (^)(NSError *error))failure;

@end
26 changes: 2 additions & 24 deletions MatrixSDK/Crypto/Algorithms/Megolm/MXMegolmDecryption.m
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ - (MXHTTPOperation*)shareKeysWithDevice:(MXIncomingRoomKeyRequest*)keyRequest
operation = [crypto ensureOlmSessionsForDevices:@{
userId: @[deviceInfo]
}
force:NO
success:^(MXUsersDevicesMap<MXOlmSessionResult *> *results)
{
MXStrongifyAndReturnIfNil(self);
Expand All @@ -323,7 +324,7 @@ - (MXHTTPOperation*)shareKeysWithDevice:(MXIncomingRoomKeyRequest*)keyRequest

NSLog(@"[MXMegolmDecryption] shareKeysWithDevice: sharing keys for session %@|%@ with device %@:%@", senderKey, sessionId, userId, deviceId);

NSDictionary *payload = [self buildKeyForwardingMessage:roomId senderKey:senderKey sessionId:sessionId];
NSDictionary *payload = [self->crypto buildMegolmKeyForwardingMessage:roomId senderKey:senderKey sessionId:sessionId chainIndex:nil];

MXDeviceInfo *deviceInfo = olmSessionResult.device;

Expand Down Expand Up @@ -463,29 +464,6 @@ - (void)requestKeysForEvent:(MXEvent*)event
}
}

- (NSDictionary*)buildKeyForwardingMessage:(NSString*)roomId senderKey:(NSString*)senderKey sessionId:(NSString*)sessionId
{
NSDictionary *key = [olmDevice getInboundGroupSessionKey:roomId senderKey:senderKey sessionId:sessionId];
if (key)
{
return @{
@"type": kMXEventTypeStringRoomForwardedKey,
@"content": @{
@"algorithm": kMXCryptoMegolmAlgorithm,
@"room_id": roomId,
@"sender_key": senderKey,
@"sender_claimed_ed25519_key": key[@"sender_claimed_ed25519_key"],
@"session_id": sessionId,
@"session_key": key[@"key"],
@"chain_index": key[@"chain_index"],
@"forwarding_curve25519_key_chain": key[@"forwarding_curve25519_key_chain"]
}
};
}

return nil;
}

@end

#endif
79 changes: 78 additions & 1 deletion MatrixSDK/Crypto/Algorithms/Megolm/MXMegolmEncryption.m
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ @interface MXMegolmEncryption ()
// that even if this is non-null, it may not be ready for use (in which
// case outboundSession.shareOperation will be non-nill.)
MXOutboundSessionInfo *outboundSession;

// Map of outbound sessions by sessions ID. Used if we need a particular
// session.
NSMutableDictionary<NSString*, MXOutboundSessionInfo*> *outboundSessions;

NSMutableArray<MXQueuedEncryption*> *pendingEncryptions;

Expand Down Expand Up @@ -112,6 +116,7 @@ - (instancetype)initWithCrypto:(MXCrypto *)theCrypto andRoom:(NSString *)theRoom
roomId = theRoomId;
deviceId = crypto.store.deviceId;

outboundSessions = [NSMutableDictionary dictionary];
pendingEncryptions = [NSMutableArray array];

// Default rotation periods
Expand Down Expand Up @@ -285,6 +290,7 @@ - (MXHTTPOperation *)ensureOutboundSession:(MXUsersDevicesMap<MXDeviceInfo *> *)
if (!session)
{
outboundSession = session = [self prepareNewSession];
outboundSessions[outboundSession.sessionId] = outboundSession;
}

if (session.shareOperation)
Expand Down Expand Up @@ -372,7 +378,7 @@ - (MXHTTPOperation*)shareKey:(MXOutboundSessionInfo*)session

MXHTTPOperation *operation;
MXWeakify(self);
operation = [crypto ensureOlmSessionsForDevices:devicesByUser success:^(MXUsersDevicesMap<MXOlmSessionResult *> *results) {
operation = [crypto ensureOlmSessionsForDevices:devicesByUser force:NO success:^(MXUsersDevicesMap<MXOlmSessionResult *> *results) {
MXStrongifyAndReturnIfNil(self);

NSLog(@"[MXMegolmEncryption] shareKey: ensureOlmSessionsForDevices result (users: %tu - devices: %tu): %@", results.map.count, results.count, results);
Expand Down Expand Up @@ -462,6 +468,77 @@ - (MXHTTPOperation*)shareKey:(MXOutboundSessionInfo*)session
return operation;
}

- (MXHTTPOperation*)reshareKey:(NSString*)sessionId
withUser:(NSString*)userId
andDevice:(NSString*)deviceId
senderKey:(NSString*)senderKey
success:(void (^)(void))success
failure:(void (^)(NSError *error))failure
{
NSLog(@"[MXMegolmEncryption] reshareKey: %@ to %@:%@", sessionId, userId, deviceId);

MXDeviceInfo *deviceInfo = [crypto.store deviceWithDeviceId:deviceId forUser:userId];
if (!deviceInfo)
{
NSLog(@"[MXMegolmEncryption] reshareKey: ERROR: Unknown device");
failure(nil);
return nil;
}

// Get the chain index of the key we previously sent this device
MXOutboundSessionInfo *obSessionInfo = outboundSessions[sessionId];
NSNumber *chainIndex = [obSessionInfo.sharedWithDevices objectForDevice:deviceId forUser:userId];
if (!chainIndex)
{
NSLog(@"[MXMegolmEncryption] reshareKey: ERROR: Never share megolm with this device");
failure(nil);
return nil;
}

MXHTTPOperation *operation;
MXWeakify(self);
operation = [crypto ensureOlmSessionsForDevices:@{
userId: @[deviceInfo]
}
force:NO
success:^(MXUsersDevicesMap<MXOlmSessionResult *> *results)
{
MXStrongifyAndReturnIfNil(self);

MXOlmSessionResult *olmSessionResult = [results objectForDevice:deviceId forUser:userId];
if (!olmSessionResult.sessionId)
{
// no session with this device, probably because there
// were no one-time keys.
//
// ensureOlmSessionsForUsers has already done the logging,
// so just skip it.
if (success)
{
success();
}
return;
}

MXDeviceInfo *deviceInfo = olmSessionResult.device;

NSLog(@"[MXMegolmEncryption] reshareKey: sharing keys for session %@|%@:%@ with device %@:%@", senderKey, sessionId, chainIndex, userId, deviceId);

NSDictionary *payload = [self->crypto buildMegolmKeyForwardingMessage:self->roomId senderKey:senderKey sessionId:sessionId chainIndex:chainIndex];


MXUsersDevicesMap<NSDictionary*> *contentMap = [[MXUsersDevicesMap alloc] init];
[contentMap setObject:[self->crypto encryptMessage:payload forDevices:@[deviceInfo]]
forUser:userId andDevice:deviceId];

MXHTTPOperation *operation2 = [self->crypto.matrixRestClient sendToDevice:kMXEventTypeStringRoomEncrypted contentMap:contentMap txnId:nil success:success failure:failure];
[operation mutateTo:operation2];

} failure:failure];

return operation;
}

- (void)processPendingEncryptionsInSession:(MXOutboundSessionInfo*)session withError:(NSError*)error
{
if (session)
Expand Down
11 changes: 11 additions & 0 deletions MatrixSDK/Crypto/Algorithms/Olm/MXOlmEncryption.m
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,17 @@ - (MXHTTPOperation*)ensureSessionForUsers:(NSArray<NSString*>*)users
return operation;
}

- (MXHTTPOperation*)reshareKey:(NSString*)sessionId
withUser:(NSString*)userId
andDevice:(NSString*)deviceId
senderKey:(NSString*)senderKey
success:(void (^)(void))success
failure:(void (^)(NSError *error))failure
{
// No need for olm
return nil;
}

@end

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,7 @@ - (MXRealmRoomAlgorithm *)realmRoomAlgorithmForRoom:(NSString*)roomId inRealm:(R

- (void)storeSession:(MXOlmSession*)session forDevice:(NSString*)deviceKey
{
BOOL isNew = NO;
__block BOOL isNew = NO;
NSDate *startDate = [NSDate date];

RLMRealm *realm = self.realm;
Expand All @@ -671,6 +671,7 @@ - (void)storeSession:(MXOlmSession*)session forDevice:(NSString*)deviceKey
else
{
// Create it
isNew = YES;
realmOlmSession = [[MXRealmOlmSession alloc] initWithValue:@{
@"sessionId": session.session.sessionIdentifier,
@"deviceKey": deviceKey,
Expand Down
26 changes: 22 additions & 4 deletions MatrixSDK/Crypto/KeySharing/MXIncomingRoomKeyRequestManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,27 @@ - (void)processReceivedRoomKeyRequest:(MXIncomingRoomKeyRequest*)req

if (![userId isEqualToString:crypto.matrixRestClient.credentials.userId])
{
// TODO: determine if we sent this device the keys already: in
// which case we can do so again.
NSLog(@"[MXIncomingRoomKeyRequestManager] Ignoring room key request from other user for now");
NSString *senderKey, *sessionId;
MXJSONModelSetString(senderKey, body[@"sender_key"]);
MXJSONModelSetString(sessionId, body[@"session_id"]);

if (!senderKey && !sessionId)
{
return;
}

id<MXEncrypting> encryptor = [crypto getRoomEncryptor:roomId algorithm:alg];
if (!encryptor)
{
NSLog(@"[MXIncomingRoomKeyRequestManager] room key request for unknown alg %@ in room %@", alg, roomId);
return;
}

[encryptor reshareKey:sessionId withUser:userId andDevice:deviceId senderKey:senderKey success:^{

} failure:^(NSError *error) {

}];
return;
}

Expand Down Expand Up @@ -170,7 +188,7 @@ - (void)processReceivedRoomKeyRequest:(MXIncomingRoomKeyRequest*)req
NSLog(@"[MXIncomingRoomKeyRequestManager] Already have this key request, ignoring");
return;
}

// Add it to pending key requests
[crypto.store storeIncomingRoomKeyRequest:req];

Expand Down
Loading