Merge branch 'sealed-sender' of github.com:RyanRory/loki-messenger-ios into dev

pull/83/head
Niels Andriesse 4 years ago
commit 4d57676c70

@ -1 +1 @@
Subproject commit a4a31c000ada50ce1be5ec6010ec13f591c899a3
Subproject commit 68cdcb17b2c087aee994bbc4de63f27d0997a4ed

@ -10,11 +10,12 @@ public final class SignalMessage : NSObject {
@objc(ttl)
public let objc_ttl: UInt64
@objc public let isPing: Bool
@objc public let isFriendRequest: Bool
public var ttl: UInt64? { return objc_ttl != 0 ? objc_ttl : nil }
@objc public init(type: SSKProtoEnvelope.SSKProtoEnvelopeType, timestamp: UInt64, senderID: String, senderDeviceID: UInt32,
content: String, recipientID: String, ttl: UInt64, isPing: Bool) {
content: String, recipientID: String, ttl: UInt64, isPing: Bool, isFriendRequest: Bool) {
self.type = type
self.timestamp = timestamp
self.senderID = senderID
@ -23,6 +24,7 @@ public final class SignalMessage : NSObject {
self.recipientID = recipientID
self.objc_ttl = ttl
self.isPing = isPing
self.isFriendRequest = isFriendRequest
super.init()
}
}

@ -480,16 +480,7 @@ NSError *EnsureDecryptError(NSError *_Nullable error, NSString *fallbackErrorDes
return failureBlock(error);
}
if (!envelope.hasServerTimestamp) {
NSString *errorDescription = @"UD Envelope is missing server timestamp.";
// TODO: We're seeing incoming UD envelopes without a server timestamp on staging.
// Until this is fixed, disabling this assert.
// OWSFailDebug(@"%@", errorDescription);
OWSLogError(@"%@", errorDescription);
NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeFailedToDecryptUDMessage, errorDescription);
return failureBlock(error);
}
UInt64 serverTimestamp = envelope.serverTimestamp;
UInt64 serverTimestamp = envelope.timestamp;
id<SMKCertificateValidator> certificateValidator =
[[SMKCertificateDefaultValidator alloc] initWithTrustRoot:self.udManager.trustRoot];
@ -599,7 +590,7 @@ NSError *EnsureDecryptError(NSError *_Nullable error, NSString *fallbackErrorDes
}
NSString *source = decryptResult.senderRecipientId;
if (source.length < 1 || !source.isValidE164) {
if (source.length < 1) {
NSString *errorDescription = @"Invalid UD sender.";
OWSFailDebug(@"%@", errorDescription);
NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeFailedToDecryptUDMessage, errorDescription);
@ -618,6 +609,10 @@ NSError *EnsureDecryptError(NSError *_Nullable error, NSString *fallbackErrorDes
SSKProtoEnvelopeBuilder *envelopeBuilder = [envelope asBuilder];
[envelopeBuilder setSource:source];
[envelopeBuilder setSourceDevice:(uint32_t)sourceDeviceId];
if (decryptResult.messageType == SMKMessageTypeLokiFriendRequest) {
[envelopeBuilder setType:SSKProtoEnvelopeTypeFriendRequest];
OWSLogInfo(@"SMKMessageTypeLokiFriendRequest");
}
NSError *envelopeBuilderError;
NSData *_Nullable newEnvelopeData = [envelopeBuilder buildSerializedDataAndReturnError:&envelopeBuilderError];
if (envelopeBuilderError || !newEnvelopeData) {

@ -264,13 +264,15 @@ NS_ASSUME_NONNULL_BEGIN
OWSLogInfo(@"handling decrypted envelope: %@", [self descriptionForEnvelope:envelope]);
if (!envelope.hasSource || envelope.source.length < 1) {
OWSFailDebug(@"incoming envelope has invalid source");
return;
}
if (!envelope.hasSourceDevice || envelope.sourceDevice < 1) {
OWSFailDebug(@"incoming envelope has invalid source device");
return;
if (!wasReceivedByUD) {
if (!envelope.hasSource || envelope.source.length < 1) {
OWSFailDebug(@"incoming envelope has invalid source");
return;
}
if (!envelope.hasSourceDevice || envelope.sourceDevice < 1) {
OWSFailDebug(@"incoming envelope has invalid source device");
return;
}
}
OWSAssertDebug(![self isEnvelopeSenderBlocked:envelope]);
@ -454,7 +456,7 @@ NS_ASSUME_NONNULL_BEGIN
TSContactThread *thread = [TSContactThread getThreadWithContactId:envelope.source transaction:transaction];
if (thread && thread.isContactFriend) {
[self resetSessionWithContact:envelope.source transaction:transaction];
// Let our other devices know that we have reset the session
// Let our o ther devices know that we have reset the session
[SSKEnvironment.shared.syncManager syncContact:envelope.source transaction:transaction];
}
}

@ -628,6 +628,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
failure:(RetryableFailureHandler)failureHandlerParam
{
AssertIsOnSendingQueue();
OWSAssert(senderCertificate);
void (^successHandler)(void) = ^() {
dispatch_async([OWSDispatch sendingQueue], ^{
@ -939,7 +940,12 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
message.skipSave = YES;
SignalRecipient *recipient = [[SignalRecipient alloc] initWithUniqueId:hexEncodedPublicKey];
NSString *userHexEncodedPublicKey = OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey;
return [[OWSMessageSend alloc] initWithMessage:message thread:thread recipient:recipient senderCertificate:nil udAccess:nil localNumber:userHexEncodedPublicKey success:^{ } failure:^(NSError *error) { }];
SMKSenderCertificate *senderCertificate = [self.udManager getSenderCertificate];
OWSUDAccess *theirUDAccess = nil;
if (senderCertificate != nil) {
theirUDAccess = [self.udManager udAccessForRecipientId:recipient.recipientId requireSyncAccess:YES];
}
return [[OWSMessageSend alloc] initWithMessage:message thread:thread recipient:recipient senderCertificate:senderCertificate udAccess:theirUDAccess localNumber:userHexEncodedPublicKey success:^{ } failure:^(NSError *error) { }];
}
- (OWSMessageSend *)getMultiDeviceFriendRequestMessageForHexEncodedPublicKey:(NSString *)hexEncodedPublicKey
@ -960,7 +966,12 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
message.skipSave = YES;
SignalRecipient *recipient = [[SignalRecipient alloc] initWithUniqueId:hexEncodedPublicKey];
NSString *userHexEncodedPublicKey = OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey;
return [[OWSMessageSend alloc] initWithMessage:message thread:thread recipient:recipient senderCertificate:nil udAccess:nil localNumber:userHexEncodedPublicKey success:^{ } failure:^(NSError *error) { }];
SMKSenderCertificate *senderCertificate = [self.udManager getSenderCertificate];
OWSUDAccess *theirUDAccess = nil;
if (senderCertificate != nil) {
theirUDAccess = [self.udManager udAccessForRecipientId:recipient.recipientId requireSyncAccess:YES];
}
return [[OWSMessageSend alloc] initWithMessage:message thread:thread recipient:recipient senderCertificate:senderCertificate udAccess:theirUDAccess localNumber:userHexEncodedPublicKey success:^{ } failure:^(NSError *error) { }];
}
- (OWSMessageSend *)getMultiDeviceSessionRequestMessageForHexEncodedPublicKey:(NSString *)hexEncodedPublicKey forThread:(TSThread *)thread
@ -1280,7 +1291,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
[message saveGroupChatServerID:groupMessage.serverID in:transaction];
[OWSPrimaryStorage.sharedManager setIDForMessageWithServerID:groupMessage.serverID to:message.uniqueId in:transaction];
}];
[self messageSendDidSucceed:messageSend deviceMessages:deviceMessages wasSentByUD:false wasSentByWebsocket:false];
[self messageSendDidSucceed:messageSend deviceMessages:deviceMessages wasSentByUD:messageSend.isUDSend wasSentByWebsocket:false];
})
.catchOn(OWSDispatch.sendingQueue, ^(NSError *error) { // The snode is unreachable
failedMessageSend(error);
@ -1302,19 +1313,20 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
NSDictionary *signalMessageInfo = deviceMessages.firstObject;
SSKProtoEnvelopeType type = ((NSNumber *)signalMessageInfo[@"type"]).integerValue;
uint64_t timestamp = message.timestamp;
NSString *senderID = userHexEncodedPublicKey;
uint32_t senderDeviceID = OWSDevicePrimaryDeviceId;
NSString *senderID = type == SSKProtoEnvelopeTypeUnidentifiedSender ? @"" : userHexEncodedPublicKey;
uint32_t senderDeviceID = type == SSKProtoEnvelopeTypeUnidentifiedSender ? 0 : OWSDevicePrimaryDeviceId;
NSString *content = signalMessageInfo[@"content"];
NSString *recipientID = signalMessageInfo[@"destination"];
uint64_t ttl = ((NSNumber *)signalMessageInfo[@"ttl"]).unsignedIntegerValue;
BOOL isPing = ((NSNumber *)signalMessageInfo[@"isPing"]).boolValue;
LKSignalMessage *signalMessage = [[LKSignalMessage alloc] initWithType:type timestamp:timestamp senderID:senderID senderDeviceID:senderDeviceID content:content recipientID:recipientID ttl:ttl isPing:isPing];
BOOL isFriendRequest = ((NSNumber *)signalMessageInfo[@"isFriendRequest"]).boolValue;
LKSignalMessage *signalMessage = [[LKSignalMessage alloc] initWithType:type timestamp:timestamp senderID:senderID senderDeviceID:senderDeviceID content:content recipientID:recipientID ttl:ttl isPing:isPing isFriendRequest:isFriendRequest];
if (!message.skipSave) {
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
// Update the PoW calculation status
[message saveIsCalculatingProofOfWork:YES withTransaction:transaction];
// Update the message and thread if needed
if (signalMessage.type == TSFriendRequestMessageType) {
if (signalMessage.isFriendRequest) {
[message.thread saveFriendRequestStatus:LKThreadFriendRequestStatusRequestSending withTransaction:transaction];
[message saveFriendRequestStatus:LKMessageFriendRequestStatusSendingOrFailed withTransaction:transaction];
}
@ -1326,7 +1338,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
if (!message.skipSave) {
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
// Update the message and thread if needed
if (signalMessage.type == TSFriendRequestMessageType) {
if (signalMessage.isFriendRequest) {
[message.thread saveFriendRequestStatus:LKThreadFriendRequestStatusNone withTransaction:transaction];
[message saveFriendRequestStatus:LKMessageFriendRequestStatusSendingOrFailed withTransaction:transaction];
}
@ -1350,7 +1362,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
if (isSuccess) { return; } // Succeed as soon as the first promise succeeds
[NSNotificationCenter.defaultCenter postNotificationName:NSNotification.messageSent object:[[NSNumber alloc] initWithUnsignedLongLong:signalMessage.timestamp]];
isSuccess = YES;
if (signalMessage.type == TSFriendRequestMessageType) {
if (signalMessage.isFriendRequest) {
if (!message.skipSave) {
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
// Update the thread
@ -1368,7 +1380,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
}
}
// Invoke the completion handler
[self messageSendDidSucceed:messageSend deviceMessages:deviceMessages wasSentByUD:false wasSentByWebsocket:false];
[self messageSendDidSucceed:messageSend deviceMessages:deviceMessages wasSentByUD:messageSend.isUDSend wasSentByWebsocket:false];
})
.catchOn(OWSDispatch.sendingQueue, ^(NSError *error) {
errorCount += 1;
@ -1671,12 +1683,18 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
recipient = [SignalRecipient markRecipientAsRegisteredAndGet:recipientId transaction:transaction];
}];
SMKSenderCertificate *senderCertificate = [self.udManager getSenderCertificate];
OWSUDAccess *theirUDAccess = nil;
if (senderCertificate != nil) {
theirUDAccess = [self.udManager udAccessForRecipientId:recipient.recipientId requireSyncAccess:YES];
}
OWSMessageSend *messageSend = [[OWSMessageSend alloc] initWithMessage:sentMessageTranscript
thread:message.thread
recipient:recipient
senderCertificate:nil
udAccess:nil
senderCertificate:senderCertificate
udAccess:theirUDAccess
localNumber:self.tsAccountManager.localNumber
success:^{
OWSLogInfo(@"Successfully sent sync transcript.");
@ -1941,7 +1959,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
isOnline:false
registrationId:0
ttl:message.ttl
isPing:false];
isPing:false
isFriendRequest:true];
NSError *error;
NSDictionary *jsonDict = [MTLJSONAdapter JSONDictionaryFromModel:messageParams error:&error];
@ -1969,14 +1988,21 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
// Loki: Both for friend request messages and device link messages we use fallback encryption as we don't necessarily have a session yet
BOOL isFriendRequest = [messageSend.message isKindOfClass:LKFriendRequestMessage.class];
<<<<<<< HEAD
BOOL isSessionRequest = [messageSend.message isKindOfClass:LKSessionRequestMessage.class];
BOOL isDeviceLinkMessage = [messageSend.message isKindOfClass:LKDeviceLinkMessage.class];
if (isFriendRequest || isSessionRequest || (isDeviceLinkMessage && ((LKDeviceLinkMessage *)messageSend.message).kind == LKDeviceLinkMessageKindRequest)) {
return [self throws_encryptedFriendRequestOrDeviceLinkMessageForMessageSend:messageSend deviceId:@(OWSDevicePrimaryDeviceId) plainText:plainText];
}
=======
BOOL isDeviceLinkMessage = [messageSend.message isKindOfClass:LKDeviceLinkMessage.class] && ((LKDeviceLinkMessage *)messageSend.message).kind == LKDeviceLinkMessageKindRequest;
// if ((isDeviceLinkMessage && ((LKDeviceLinkMessage *)messageSend.message).kind == LKDeviceLinkMessageKindRequest)) {
// return [self throws_encryptedFriendRequestOrDeviceLinkMessageForMessageSend:messageSend deviceId:@(OWSDevicePrimaryDeviceId) plainText:plainText];
// }
>>>>>>> f4e376bfb47d670f29ab970912d4004f694c1d69
// This may throw an exception.
if (![storage containsSession:recipientID deviceId:@(OWSDevicePrimaryDeviceId).intValue protocolContext:transaction]) {
if (!isFriendRequest && !isDeviceLinkMessage && ![storage containsSession:recipientID deviceId:@(OWSDevicePrimaryDeviceId).intValue protocolContext:transaction]) {
NSString *missingSessionException = @"missingSessionException";
OWSRaiseException(missingSessionException,
@"Unexpectedly missing session for recipient: %@, device: %@",
@ -2010,6 +2036,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
paddedPlaintext:[plainText paddedMessageBody]
senderCertificate:messageSend.senderCertificate
protocolContext:transaction
isFriendRequest:isFriendRequest || isDeviceLinkMessage
error:&error];
SCKRaiseIfExceptionWrapperError(error);
if (!serializedMessage || error) {
@ -2039,7 +2066,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
isOnline:isOnline
registrationId:[cipher throws_remoteRegistrationId:transaction]
ttl:message.ttl
isPing:isPing];
isPing:isPing
isFriendRequest:isFriendRequest || isDeviceLinkMessage];
NSError *error;
NSDictionary *jsonDict = [MTLJSONAdapter JSONDictionaryFromModel:messageParams error:&error];

@ -30,6 +30,9 @@ NS_ASSUME_NONNULL_BEGIN
// Loki: Wether this message is a p2p ping
@property (nonatomic, readonly) BOOL isPing;
// Loki: Wether this message is a friend request
@property (nonatomic, readonly) BOOL isFriendRequest;
- (instancetype)initWithType:(TSWhisperMessageType)type
recipientId:(NSString *)destination
device:(int)deviceId
@ -38,7 +41,8 @@ NS_ASSUME_NONNULL_BEGIN
isOnline:(BOOL)isOnline
registrationId:(int)registrationId
ttl:(uint)ttl
isPing:(BOOL)isPing;
isPing:(BOOL)isPing
isFriendRequest:(BOOL)isFriendRequest;
@end

@ -24,6 +24,7 @@ NS_ASSUME_NONNULL_BEGIN
registrationId:(int)registrationId
ttl:(uint)ttl
isPing:(BOOL)isPing
isFriendRequest:(BOOL)isFriendRequest
{
self = [super init];
@ -40,6 +41,7 @@ NS_ASSUME_NONNULL_BEGIN
_online = isOnline;
_ttl = ttl;
_isPing = isPing;
_isFriendRequest = isFriendRequest;
return self;
}

@ -100,6 +100,9 @@ public class OWSUDAccess: NSObject {
func shouldAllowUnrestrictedAccessLocal() -> Bool
@objc
func setShouldAllowUnrestrictedAccessLocal(_ value: Bool)
@objc
func getSenderCertificate() -> SMKSenderCertificate?
}
// MARK: -
@ -408,6 +411,7 @@ public class OWSUDManagerImpl: NSObject, OWSUDManager {
}
public func ensureSenderCertificate(certificateExpirationPolicy: OWSUDCertificateExpirationPolicy) -> Promise<SMKSenderCertificate> {
<<<<<<< HEAD
return Promise(error: "Disabled.")
// If there is a valid cached sender certificate, use that.
//
@ -416,9 +420,11 @@ public class OWSUDManagerImpl: NSObject, OWSUDManager {
return Promise.value(certificate)
}
=======
>>>>>>> f4e376bfb47d670f29ab970912d4004f694c1d69
// Try to obtain a new sender certificate.
return firstly {
requestSenderCertificate()
generateSenderCertificate()
}.map { (certificateData: Data, certificate: SMKSenderCertificate) in
// Cache the current sender certificate.
@ -427,6 +433,34 @@ public class OWSUDManagerImpl: NSObject, OWSUDManager {
return certificate
}
}
private func generateSenderCertificate() -> Promise<(certificateData: Data, certificate: SMKSenderCertificate)> {
return Promise<(certificateData: Data, certificate: SMKSenderCertificate)> { seal in
//Loki: Generate a sender certifate locally
let sender = OWSIdentityManager.shared().identityKeyPair()?.hexEncodedPublicKey
let certificate = SMKSenderCertificate(senderDeviceId: OWSDevicePrimaryDeviceId, senderRecipientId: sender!)
let certificateData = try certificate.serialized()
guard self.isValidCertificate(certificate) else {
throw OWSUDError.invalidData(description: "Invalid sender certificate returned by server")
}
seal.fulfill((certificateData: certificateData, certificate: certificate))
}
}
@objc
public func getSenderCertificate() -> SMKSenderCertificate? {
do {
let sender = OWSIdentityManager.shared().identityKeyPair()?.hexEncodedPublicKey
let certificate = SMKSenderCertificate(senderDeviceId: OWSDevicePrimaryDeviceId, senderRecipientId: sender!)
guard self.isValidCertificate(certificate) else {
throw OWSUDError.invalidData(description: "Invalid sender certificate returned by server")
}
return certificate
} catch {
Logger.error("\(error)")
return nil
}
}
private func requestSenderCertificate() -> Promise<(certificateData: Data, certificate: SMKSenderCertificate)> {
return firstly {

Loading…
Cancel
Save