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

Simplify user verification state #1740

Merged
merged 2 commits into from
Mar 20, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
66 changes: 36 additions & 30 deletions MatrixSDK.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions MatrixSDK/Crypto/CrossSigning/Data/MXCrossSigningInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
#import <Foundation/Foundation.h>

#import "MXCrossSigningKey.h"
#import "MXUserTrustLevel.h"

@class MXCryptoUserIdentityWrapper;

Expand Down Expand Up @@ -56,7 +55,7 @@ extern NSString *const MXCrossSigningInfoTrustLevelDidChangeNotification;

#pragma mark - Additional information

@property (nonatomic, readonly) MXUserTrustLevel *trustLevel;
@property (nonatomic, readonly) BOOL isVerified;

@end

Expand Down
81 changes: 61 additions & 20 deletions MatrixSDK/Crypto/CrossSigning/Data/MXCrossSigningInfo.m
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,40 @@

NSString *const MXCrossSigningInfoTrustLevelDidChangeNotification = @"MXCrossSigningInfoTrustLevelDidChangeNotification";

#pragma mark - Deprecated user trust

/**
Deprecated model of user trust that distinguished local vs cross-signing verification

This model is no longer used and is replaced by a combined `isVerified` property on `MXCrossSigningInfo`.
For backwards compatibility (reading archived values) the model needs to be kept around, albeit as private only.
*/
@interface MXDeprecatedUserTrustLevel : NSObject <NSCoding>
@property (nonatomic, readonly) BOOL isCrossSigningVerified;
@property (nonatomic, readonly) BOOL isLocallyVerified;
@end

@implementation MXDeprecatedUserTrustLevel
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if (self)
{
_isCrossSigningVerified = [aDecoder decodeBoolForKey:@"isCrossSigningVerified"];
_isLocallyVerified = [aDecoder decodeBoolForKey:@"isLocallyVerified"];
}
return self;
}

- (void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeBool:_isCrossSigningVerified forKey:@"isCrossSigningVerified"];
[aCoder encodeBool:_isLocallyVerified forKey:@"isLocallyVerified"];
}
@end

#pragma mark - CrossSigningInfo

@implementation MXCrossSigningInfo

- (instancetype)initWithUserIdentity:(MXCryptoUserIdentityWrapper *)userIdentity
Expand All @@ -43,7 +77,7 @@ - (instancetype)initWithUserIdentity:(MXCryptoUserIdentityWrapper *)userIdentity
keys[MXCrossSigningKeyType.userSigning] = userIdentity.userSignedKeys;
}
_keys = keys.copy;
_trustLevel = userIdentity.trustLevel;
_isVerified = userIdentity.isVerified;
}
return self;
}
Expand Down Expand Up @@ -92,7 +126,21 @@ - (id)initWithCoder:(NSCoder *)aDecoder
{
_userId = [aDecoder decodeObjectForKey:@"userId"];
_keys = [aDecoder decodeObjectForKey:@"keys"];
_trustLevel = [aDecoder decodeObjectForKey:@"trustLevel"];

// Initial version (i.e. version 0) of the model stored user trust via `MXUserTrustLevel` submodel.
// If we are reading this version out we need to decode verification state from this model before
// migrating it over to `isVerified`
NSInteger version = [aDecoder decodeIntegerForKey:@"version"];
if (version == 0)
{
[NSKeyedUnarchiver setClass:MXDeprecatedUserTrustLevel.class forClassName:@"MXUserTrustLevel"];
MXDeprecatedUserTrustLevel *trust = [aDecoder decodeObjectForKey:@"trustLevel"];
_isVerified = trust.isLocallyVerified || trust.isCrossSigningVerified;
}
else
{
_isVerified = [aDecoder decodeBoolForKey:@"isVerified"];
}
}
return self;
}
Expand All @@ -101,7 +149,8 @@ - (void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:_userId forKey:@"userId"];
[aCoder encodeObject:_keys forKey:@"keys"];
[aCoder encodeObject:_trustLevel forKey:@"trustLevel"];
[aCoder encodeBool:_isVerified forKey:@"isVerified"];
[aCoder encodeInteger:1 forKey:@"version"];
}


Expand All @@ -113,31 +162,23 @@ - (instancetype)initWithUserId:(NSString *)userId
if (self)
{
_userId = userId;
_trustLevel = [MXUserTrustLevel new];
_isVerified = NO;
}
return self;
}

- (void)setTrustLevel:(MXUserTrustLevel*)trustLevel
{
_trustLevel = trustLevel;
}

- (BOOL)updateTrustLevel:(MXUserTrustLevel*)trustLevel
- (void)setIsVerified:(BOOL)isVerified
{
BOOL updated = NO;

if (![_trustLevel isEqual:trustLevel])
if (_isVerified == isVerified)
{
_trustLevel = trustLevel;
updated = YES;
[self didUpdateTrustLevel];
return;
}

return updated;

_isVerified = isVerified;
[self didUpdateVerificationState];
}

- (void)didUpdateTrustLevel
- (void)didUpdateVerificationState
{
dispatch_async(dispatch_get_main_queue(),^{
[[NSNotificationCenter defaultCenter] postNotificationName:MXCrossSigningInfoTrustLevelDidChangeNotification object:self userInfo:nil];
Expand All @@ -158,7 +199,7 @@ - (void)addCrossSigningKey:(MXCrossSigningKey*)crossSigningKey type:(NSString*)t

- (NSString *)description
{
return [NSString stringWithFormat:@"<MXCrossSigningInfo: %p> Trusted: %@\nMSK: %@\nSSK: %@\nUSK: %@", self, @(self.trustLevel.isCrossSigningVerified), self.masterKeys, self.selfSignedKeys, self.userSignedKeys];
return [NSString stringWithFormat:@"<MXCrossSigningInfo: %p> Verified: %@\nMSK: %@\nSSK: %@\nUSK: %@", self, @(self.isVerified), self.masterKeys, self.selfSignedKeys, self.userSignedKeys];
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ NS_ASSUME_NONNULL_BEGIN

- (instancetype)initWithUserId:(NSString *)userId;

- (void)setTrustLevel:(MXUserTrustLevel*)trustLevel;
- (BOOL)updateTrustLevel:(MXUserTrustLevel*)trustLevel;
- (void)setIsVerified:(BOOL)isVerified;
- (void)addCrossSigningKey:(MXCrossSigningKey*)crossSigningKey type:(NSString*)type;

@end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import MatrixSDKCrypto
public let masterKeys: MXCrossSigningKey?
public let selfSignedKeys: MXCrossSigningKey?
public let userSignedKeys: MXCrossSigningKey?
public let trustLevel: MXUserTrustLevel
public let isVerified: Bool

internal init(identity: UserIdentity, isVerified: Bool) {
switch identity {
Expand All @@ -43,13 +43,7 @@ import MatrixSDKCrypto
self.selfSignedKeys = .init(jsonString: selfSigningKey)
self.userSignedKeys = nil
}

// `MatrixSDKCrypto` does not distinguish local and cross-signed
// verification status for users
trustLevel = MXUserTrustLevel(
crossSigningVerified: isVerified,
locallyVerified: isVerified
)
self.isVerified = isVerified
}
}

Expand Down
19 changes: 8 additions & 11 deletions MatrixSDK/Crypto/CrossSigning/MXCrossSigning.m
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ - (void)setupWithAuthParams:(NSDictionary*)authParams
[self.crypto.matrixRestClient uploadDeviceSigningKeys:signingKeys authParams:authParams success:^{

// Store our user's keys
[keys updateTrustLevel:[MXUserTrustLevel trustLevelWithCrossSigningVerified:YES locallyVerified:YES]];
[keys setIsVerified:YES];
[self.crypto.store storeCrossSigningKeys:keys];

// Cross-signing is bootstrapped
Expand Down Expand Up @@ -585,7 +585,7 @@ - (BOOL)isDeviceVerified:(MXDeviceInfo*)device
BOOL isDeviceVerified = NO;

MXCrossSigningInfo *userCrossSigning = [self.crypto.store crossSigningKeysForUser:device.userId];
MXUserTrustLevel *userTrustLevel = [self.crypto trustLevelForUser:device.userId];
BOOL isUserVerified = [self.crypto isUserVerified:device.userId];

MXCrossSigningKey *userSSK = userCrossSigning.selfSignedKeys;
if (!userSSK)
Expand All @@ -610,7 +610,7 @@ - (BOOL)isDeviceVerified:(MXDeviceInfo*)device
// ...then we trust this device as much as far as we trust the user
if (userSSKVerify && deviceVerify)
{
isDeviceVerified = userTrustLevel.isCrossSigningVerified;
isDeviceVerified = isUserVerified;
}

return isDeviceVerified;
Expand Down Expand Up @@ -685,17 +685,14 @@ - (void)resetTrust
for (MXCrossSigningInfo *crossSigningInfo in self.crypto.store.crossSigningKeys)
{
BOOL isCrossSigningVerified = [self isUserWithCrossSigningKeysVerified:crossSigningInfo];
if (crossSigningInfo.trustLevel.isCrossSigningVerified != isCrossSigningVerified)
if (crossSigningInfo.isVerified != isCrossSigningVerified)
{
MXLogDebug(@"[MXCrossSigning] resetTrust: Change trust for %@: %@ -> %@", crossSigningInfo.userId,
@(crossSigningInfo.trustLevel.isCrossSigningVerified),
@(crossSigningInfo.isVerified),
@(isCrossSigningVerified));

MXUserTrustLevel *newTrustLevel = [MXUserTrustLevel trustLevelWithCrossSigningVerified:isCrossSigningVerified locallyVerified:crossSigningInfo.trustLevel.isLocallyVerified];
if ([crossSigningInfo updateTrustLevel:newTrustLevel])
{
[self.crypto.store storeCrossSigningKeys:crossSigningInfo];
}
[crossSigningInfo setIsVerified:isCrossSigningVerified];
[self.crypto.store storeCrossSigningKeys:crossSigningInfo];

// Update trust on associated devices
[self checkTrustLevelForDevicesOfUser:crossSigningInfo.userId];
Expand Down Expand Up @@ -747,7 +744,7 @@ - (BOOL)isSelfTrusted

// Is the master key trusted?
MXCrossSigningInfo *myCrossSigningInfo = [_crypto.store crossSigningKeysForUser:myUserId];
if (myCrossSigningInfo && myCrossSigningInfo.trustLevel.isLocallyVerified)
if (myCrossSigningInfo && myCrossSigningInfo.isVerified)
{
isMasterKeyTrusted = YES;
}
Expand Down
12 changes: 3 additions & 9 deletions MatrixSDK/Crypto/CrossSigning/MXCrossSigningV2.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class MXCrossSigningV2: NSObject, MXCrossSigning {
return .notBootstrapped
}

if info.trustLevel.isVerified {
if info.isVerified {
return hasAllPrivateKeys ? .canCrossSign : .trustCrossSigning
} else {
return .crossSigningExists
Expand Down Expand Up @@ -217,17 +217,11 @@ class MXCrossSigningV2: NSObject, MXCrossSigning {
}

extension MXCrossSigningV2: MXRecoveryServiceDelegate {
func setUserVerification(
_ verificationStatus: Bool,
forUser userId: String,
func setUserVerificationForUserId(
_ userId: String,
success: @escaping () -> Void,
failure: @escaping (Swift.Error?) -> Void
) {
guard verificationStatus else {
log.failure("Cannot unset user trust")
failure(Error.cannotUnsetTrust)
return
}
signUser(withUserId: userId, success: success, failure: failure)
}
}
15 changes: 1 addition & 14 deletions MatrixSDK/Crypto/Data/MXDeviceListOperationsPool.m
Original file line number Diff line number Diff line change
Expand Up @@ -137,24 +137,11 @@ - (void)doKeyDownloadForUsers:(NSArray<NSString *> *)users token:(NSString *)tok
MXLogDebug(@"[MXDeviceListOperationsPool] doKeyDownloadForUsers: Detected cross-signing keys rotation");
myUserCrossSigningKeysChanged = YES;
}

// Use current trust level
MXUserTrustLevel *oldTrustLevel = storedCrossSigningKeys.trustLevel;
if (myUserCrossSigningKeysChanged)
{
// Except if we cannot trust it anymore
oldTrustLevel = [MXUserTrustLevel new];
}

[crossSigningKeys setTrustLevel:oldTrustLevel];

// Compute trust on this user
// Note this overwrites the previous value
BOOL isCrossSigningVerified = [self.crossSigning isUserWithCrossSigningKeysVerified:crossSigningKeys];
MXUserTrustLevel *newTrustLevel = [MXUserTrustLevel trustLevelWithCrossSigningVerified:isCrossSigningVerified
locallyVerified:oldTrustLevel.isLocallyVerified];

[crossSigningKeys updateTrustLevel:newTrustLevel];
[crossSigningKeys setIsVerified:isCrossSigningVerified];

// Note that keys which aren't in the response will be removed from the store
[self->crypto.store storeCrossSigningKeys:crossSigningKeys];
Expand Down
15 changes: 9 additions & 6 deletions MatrixSDK/Crypto/MXCrypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,19 +229,22 @@ extern NSString *const MXDeviceListDidUpdateUsersDevicesNotification;
failure:(nullable void (^)(NSError *error))failure;

/**
Update the verification state of the given user.
Verify the given user via cross-signing

@param verificationStatus the new verification status.
@param userId the user.

@param success A block object called when the operation succeeds.
@param failure A block object called when the operation fails.
*/
- (void)setUserVerification:(BOOL)verificationStatus forUser:(NSString*)userId
success:(nullable void (^)(void))success
failure:(nullable void (^)(NSError *error))failure;
- (void)setUserVerificationForUserId:(NSString*)userId
success:(nullable void (^)(void))success
failure:(nullable void (^)(NSError *error))failure;

/**
Is the user verified via cross-signing
*/
- (BOOL)isUserVerified:(NSString *)userId;

- (MXUserTrustLevel*)trustLevelForUser:(NSString*)userId;
- (nullable MXDeviceTrustLevel*)deviceTrustLevelForDevice:(NSString*)deviceId ofUser:(NSString*)userId;

/**
Expand Down
Loading