Skip to content
Draft
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
134 changes: 88 additions & 46 deletions MatrixSDK/Crypto/MXCrypto.m
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
// Frequency with which to check & upload one-time keys
NSTimeInterval kMXCryptoUploadOneTimeKeysPeriod = 60.0; // one minute
NSTimeInterval kMXCryptoMinForceSessionPeriod = 3600.0; // one hour
NSTimeInterval kXCryptoDefaultForgetFallbackKeyInterval = 3600.0; // one hour

@interface MXCrypto ()
{
Expand Down Expand Up @@ -127,9 +128,6 @@ @interface MXCrypto ()
MXCryptoMigration *cryptoMigration;
}

// The current fallback key operation, if any
@property(nonatomic, strong) MXHTTPOperation *uploadFallbackKeyOperation;

@end

#endif
Expand Down Expand Up @@ -399,9 +397,6 @@ - (void)close:(BOOL)deleteStore
// Cancel pending one-time keys upload
[self->uploadOneTimeKeysOperation cancel];
self->uploadOneTimeKeysOperation = nil;

[self.uploadFallbackKeyOperation cancel];
self.uploadFallbackKeyOperation = nil;

[self->outgoingRoomKeyRequestManager close];
self->outgoingRoomKeyRequestManager = nil;
Expand Down Expand Up @@ -854,6 +849,9 @@ - (void)handleDeviceOneTimeKeysCount:(NSDictionary<NSString *, NSNumber*>*)devic
- (void)handleDeviceUnusedFallbackKeys:(NSArray<NSString *> *)deviceFallbackKeys
{
#ifdef MX_CRYPTO

MXLogDebug(@"[MXCrypto] handleDeviceUnusedFallbackKeys: sync response has fallback %i", [deviceFallbackKeys containsObject:kMXKeySignedCurve25519Type]);

if (deviceFallbackKeys == nil) {
return;
}
Expand All @@ -862,14 +860,12 @@ - (void)handleDeviceUnusedFallbackKeys:(NSArray<NSString *> *)deviceFallbackKeys
return;
}

if (self.uploadFallbackKeyOperation)
{
MXLogDebug(@"[MXCrypto] handleDeviceUnusedFallbackKeys: Fallback key upload already in progress.");
return;
}

// We will be checking this often enough for it not to warrant automatic retries.
self.uploadFallbackKeyOperation = [self generateAndUploadFallbackKey];
MXWeakify(self);
dispatch_async(_cryptoQueue, ^{
MXStrongifyAndReturnIfNil(self);
[self generateFallbackKeyIfNeeded];
});

#endif
}

Expand Down Expand Up @@ -2782,8 +2778,22 @@ - (void)maybeUploadOneTimeKeys:(void (^)(void))success failure:(void (^)(NSError
}

lastOneTimeKeyCheck = now;


NSDate *lastFallbackKeyUploadTime = [self lastFallbackKeyUploadTime];
MXLogDebug(@"[MXCrypto] lastFallbackKeyUploadTime: %@", lastFallbackKeyUploadTime);
if (lastFallbackKeyUploadTime
&& [now timeIntervalSinceDate:lastFallbackKeyUploadTime] > kXCryptoDefaultForgetFallbackKeyInterval)
{
MXLogDebug(@"[MXCrypto] maybeUploadOneTimeKeys: Can forget a fallbackKey");
[self setLastFallbackKeyUploadTime:nil];
[_olmDevice forgetFallbackKey];
}


BOOL hasUnpublishedFallbackKey = [self hasUnpublishedFallbackKey];

if (oneTimeKeyCount != -1)
if (oneTimeKeyCount != -1 || hasUnpublishedFallbackKey)
{
// We already have the current one_time_key count from a /sync response.
// Use this value instead of asking the server for the current key count.
Expand Down Expand Up @@ -2822,6 +2832,8 @@ - (void)maybeUploadOneTimeKeys:(void (^)(void))success failure:(void (^)(NSError
}
else
{

MXLogDebug(@"[MXCrypto] maybeUploadOneTimeKeys: No one time key count from sync, getting from server");
// Ask the server how many keys we have
MXWeakify(self);
uploadOneTimeKeysOperation = [self publishedOneTimeKeysCount:^(NSUInteger keyCount) {
Expand Down Expand Up @@ -2884,13 +2896,29 @@ - (void)maybeUploadOneTimeKeys:(void (^)(void))success failure:(void (^)(NSError
}
}

- (NSString *) fallbackKeyPrefKey
{
return [NSString stringWithFormat:@"%@|%@", @"lastFallBackkeyUploadTime", _olmDevice.deviceEd25519Key];
}

- (void) setLastFallbackKeyUploadTime: (NSDate *) date
{
[[NSUserDefaults standardUserDefaults] setObject:date forKey:self.fallbackKeyPrefKey];
}

- (NSDate *) lastFallbackKeyUploadTime
{
return (NSDate *) [[NSUserDefaults standardUserDefaults] objectForKey:self.fallbackKeyPrefKey];
}


- (MXHTTPOperation *)generateAndUploadOneTimeKeys:(NSUInteger)keyCount retry:(BOOL)retry success:(void (^)(void))success failure:(void (^)(NSError *))failure
{
MXLogDebug(@"[MXCrypto] generateAndUploadOneTimeKeys: %@ one time keys are available on the homeserver", @(keyCount));

MXHTTPOperation *operation;

if ([self generateOneTimeKeys:keyCount])
if ([self generateOneTimeKeys:keyCount] || [self hasUnpublishedFallbackKey])
{
operation = [self uploadOneTimeKeys:^(MXKeysUploadResponse *keysUploadResponse) {
success();
Expand Down Expand Up @@ -2918,38 +2946,28 @@ - (MXHTTPOperation *)generateAndUploadOneTimeKeys:(NSUInteger)keyCount retry:(BO
return operation;
}

- (MXHTTPOperation *)generateAndUploadFallbackKey
- (BOOL) hasUnpublishedFallbackKey
{
[_olmDevice generateFallbackKey];

NSDictionary *fallbackKey = _olmDevice.fallbackKey;
NSMutableDictionary *fallbackKeyJson = [NSMutableDictionary dictionary];

for (NSString *keyId in fallbackKey[kMXKeyCurve25519Type])
NSDictionary *fallbackDict = _olmDevice.unpublishedFallbackKey;
if (![fallbackDict[kMXKeyCurve25519Type] isKindOfClass:NSDictionary.class])
{
// Sign the fallback key
NSMutableDictionary *signedKey = [NSMutableDictionary dictionary];
signedKey[@"key"] = fallbackKey[kMXKeyCurve25519Type][keyId];
signedKey[@"fallback"] = @(YES);
signedKey[@"signatures"] = [self signObject:signedKey];

fallbackKeyJson[[NSString stringWithFormat:@"%@:%@", kMXKeySignedCurve25519Type, keyId]] = signedKey;
MXLogDebug(@"[MXCrypto] malformed fallback key: %@", fallbackDict);
return false;
}

MXLogDebug(@"[MXCrypto] generateAndUploadFallbackKey: Started uploading fallback key.");

MXWeakify(self);
return [_matrixRestClient uploadKeys:nil oneTimeKeys:nil fallbackKeys:fallbackKeyJson success:^(MXKeysUploadResponse *keysUploadResponse) {
MXStrongifyAndReturnIfNil(self);

self.uploadFallbackKeyOperation = nil;
MXLogDebug(@"[MXCrypto] generateAndUploadFallbackKey: Finished uploading fallback key.");
} failure:^(NSError *error) {
MXStrongifyAndReturnIfNil(self);

self.uploadFallbackKeyOperation = nil;
MXLogError(@"[MXCrypto] generateAndUploadFallbackKey: Failed uploading fallback key.");
}];
NSDictionary *keys = fallbackDict[kMXKeyCurve25519Type];
return [keys count] != 0;
}

- (BOOL) generateFallbackKeyIfNeeded
{
if (![self hasUnpublishedFallbackKey]) {
MXLogDebug(@"[MXCrypto] Generate new Fallback key");
[self.olmDevice generateFallbackKey];
[self setLastFallbackKeyUploadTime: nil];
return true;
}
return false;
}

/**
Expand Down Expand Up @@ -3025,16 +3043,40 @@ - (MXHTTPOperation *)uploadOneTimeKeys:(void (^)(MXKeysUploadResponse *keysUploa

oneTimeJson[[NSString stringWithFormat:@"%@:%@", kMXKeySignedCurve25519Type, keyId]] = k;
}

NSDictionary *fallbackKey = _olmDevice.unpublishedFallbackKey;
NSMutableDictionary *fallbackKeyJson = nil;

BOOL hadUnpublishedFallbackKey = [self hasUnpublishedFallbackKey];
if (hadUnpublishedFallbackKey) {
fallbackKeyJson = [NSMutableDictionary dictionary];

for (NSString *keyId in fallbackKey[kMXKeyCurve25519Type])
{
// Sign the fallback key
NSMutableDictionary *signedKey = [NSMutableDictionary dictionary];
signedKey[@"key"] = fallbackKey[kMXKeyCurve25519Type][keyId];
signedKey[@"fallback"] = @(YES);
signedKey[@"signatures"] = [self signObject:signedKey];

fallbackKeyJson[[NSString stringWithFormat:@"%@:%@", kMXKeySignedCurve25519Type, keyId]] = signedKey;
}
}

MXLogDebug(@"[MXCrypto] uploadOneTimeKeys: Upload %tu keys", ((NSDictionary*)oneTimeKeys[kMXKeyCurve25519Type]).count);
MXLogDebug(@"[MXCrypto] uploadOneTimeKeys: with fallback key %@", hadUnpublishedFallbackKey ? @"YES" : @"NO");

// For now, we set the device id explicitly, as we may not be using the
// same one as used in login.
MXWeakify(self);
return [_matrixRestClient uploadKeys:nil oneTimeKeys:oneTimeJson fallbackKeys:nil success:^(MXKeysUploadResponse *keysUploadResponse) {
MXWeakify(self);
return [_matrixRestClient uploadKeys:nil oneTimeKeys:oneTimeJson fallbackKeys:fallbackKeyJson success:^(MXKeysUploadResponse *keysUploadResponse) {
MXStrongifyAndReturnIfNil(self);

[self.olmDevice markOneTimeKeysAsPublished];
if (hadUnpublishedFallbackKey){
NSDate* now = [NSDate date];
[self setLastFallbackKeyUploadTime: now];
}
success(keysUploadResponse);

} failure:^(NSError *error) {
Expand Down
11 changes: 10 additions & 1 deletion MatrixSDK/Crypto/MXOlmDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,21 +91,30 @@
*/
- (void)markOneTimeKeysAsPublished;

- (void)forgetFallbackKey;

/**
Generate some new one-time keys

@param numKeys the number of keys to generate
*/
- (void)generateOneTimeKeys:(NSUInteger)numKeys;

/**
Deprectaded : Use unpublishedFallbackKey
*/
@property (nonatomic, readonly) NSDictionary *fallbackKey;


/**
The current fallback key for this account.

@return a dictionary with one key which is "curve25519".
Its value is a dictionary where keys are keys ids
and values, the Curve25519 keys.
*/
@property (nonatomic, readonly) NSDictionary *fallbackKey;
@property (nonatomic, readonly) NSDictionary *unpublishedFallbackKey;


/**
Generate a new fallback key
Expand Down
15 changes: 15 additions & 0 deletions MatrixSDK/Crypto/MXOlmDevice.m
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ - (NSUInteger)maxNumberOfOneTimeKeys

- (void)markOneTimeKeysAsPublished
{
MXLogDebug(@"[MXOlmDevice] markOneTimeKeysAsPublished");
[store performAccountOperationWithBlock:^(OLMAccount *olmAccount) {
[olmAccount markOneTimeKeysAsPublished];
}];
Expand All @@ -146,6 +147,20 @@ - (NSDictionary *)fallbackKey
return store.account.fallbackKey;
}

- (void)forgetFallbackKey
{
MXLogDebug(@"[MXOlmDevice] markOneTimeKeysAsPublished");
[store performAccountOperationWithBlock:^(OLMAccount *olmAccount) {
[olmAccount forgetFallbackKey];
}];
}


- (NSDictionary *)unpublishedFallbackKey
{
return [store.account unpublishedFallbackKey];
}

- (void)generateFallbackKey
{
[store performAccountOperationWithBlock:^(OLMAccount *olmAccount) {
Expand Down