Skip to content

Commit

Permalink
Merge pull request #778 from matrix-org/riot_2129
Browse files Browse the repository at this point in the history
MXCrypto: Restart broken Olm sessions
  • Loading branch information
manuroe committed Feb 10, 2020
2 parents 0e7752c + e09dde6 commit a8f5317
Show file tree
Hide file tree
Showing 12 changed files with 406 additions and 39 deletions.
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

0 comments on commit a8f5317

Please sign in to comment.