Compare commits
34 Commits
mkirk/fixu
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
06c654a757 | ||
|
|
36601e4bbe | ||
|
|
9413e47751 | ||
|
|
c40a9fb072 | ||
|
|
18a7031342 | ||
|
|
43aa55e6be | ||
|
|
89c447b636 | ||
|
|
170acafbc8 | ||
|
|
99d700a87c | ||
|
|
582ec1a96c | ||
|
|
8f8d565412 | ||
|
|
0516a98a55 | ||
|
|
f0632b87bb | ||
|
|
97ae15634e | ||
|
|
34073098e9 | ||
|
|
61ce278894 | ||
|
|
852d43fe8d | ||
|
|
debc5cb311 | ||
|
|
6a1c548be0 | ||
|
|
97bc4ea101 | ||
|
|
ddcdbd04da | ||
|
|
905c5d0e0c | ||
|
|
fb8ca529ae | ||
|
|
4a4899ea14 | ||
|
|
1c5425eb26 | ||
|
|
8d4451262d | ||
|
|
832cb97c95 | ||
|
|
9bdcbaade2 | ||
|
|
d1739b2669 | ||
|
|
3fe60a30fe | ||
|
|
41c6a84b46 | ||
|
|
aa4b0a7bfa | ||
|
|
f852496e31 | ||
|
|
dedb0f987a |
@ -11,7 +11,7 @@ Pod::Spec.new do |s|
|
||||
s.source_files = "AxolotlKit/Classes/**/*.{h,m,swift}", "AxolotlKit/Private/*.{h,m,swift}"
|
||||
s.public_header_files = "AxolotlKit/Classes/**/*.{h}"
|
||||
s.prefix_header_file = "AxolotlKit/SPKPrefix.h"
|
||||
s.ios.deployment_target = "9.0"
|
||||
s.ios.deployment_target = "10.0"
|
||||
s.osx.deployment_target = "10.8"
|
||||
s.requires_arc = true
|
||||
|
||||
|
||||
@ -310,6 +310,7 @@
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
English,
|
||||
en,
|
||||
);
|
||||
mainGroup = B6B98F6F197D838A00B16B5E;
|
||||
@ -526,7 +527,7 @@
|
||||
"$(inherited)",
|
||||
);
|
||||
INFOPLIST_FILE = "AxolotlKit/AxolotlKit-Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.whispersystems.SignalProtocolKitTestApp;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
WRAPPER_EXTENSION = app;
|
||||
@ -543,7 +544,7 @@
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "";
|
||||
INFOPLIST_FILE = "AxolotlKit/AxolotlKit-Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.whispersystems.SignalProtocolKitTestApp;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
WRAPPER_EXTENSION = app;
|
||||
@ -639,7 +640,7 @@
|
||||
"$(inherited)",
|
||||
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
|
||||
);
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
@ -685,7 +686,7 @@
|
||||
"$(inherited)",
|
||||
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
|
||||
);
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
|
||||
@ -1,13 +1,11 @@
|
||||
//
|
||||
// AxolotlKeyFetch.h
|
||||
// AxolotlKit
|
||||
//
|
||||
// Created by Frederic Jacobs on 21/07/14.
|
||||
// Copyright (c) 2014 Frederic Jacobs. All rights reserved.
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface PreKeyBundle : NSObject <NSSecureCoding>
|
||||
|
||||
@property (nonatomic, readonly) NSData *identityKey;
|
||||
@ -29,3 +27,5 @@
|
||||
identityKey:(NSData *)identityKey;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@ -1,13 +1,10 @@
|
||||
//
|
||||
// AxolotlKeyFetch.m
|
||||
// AxolotlKit
|
||||
//
|
||||
// Created by Frederic Jacobs on 21/07/14.
|
||||
// Copyright (c) 2014 Frederic Jacobs. All rights reserved.
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "PreKeyBundle.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
static NSString* const kCoderPKBIdentityKey = @"kCoderPKBIdentityKey";
|
||||
static NSString* const kCoderPKBregistrationId = @"kCoderPKBregistrationId";
|
||||
@ -62,7 +59,8 @@ static NSString* const kCoderPKBsignedPreKeySignature = @"kCoderPKBsignedPreKeyS
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)aDecoder{
|
||||
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder
|
||||
{
|
||||
int registrationId = [aDecoder decodeIntForKey:kCoderPKBregistrationId];
|
||||
int deviceId = [aDecoder decodeIntForKey:kCoderPKBdeviceId];
|
||||
int preKeyId = [aDecoder decodeIntForKey:kCoderPKBpreKeyId];
|
||||
@ -103,3 +101,5 @@ static NSString* const kCoderPKBsignedPreKeySignature = @"kCoderPKBsignedPreKeyS
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@ -5,12 +5,20 @@
|
||||
#import <Curve25519Kit/Curve25519.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface PreKeyRecord : NSObject <NSSecureCoding>
|
||||
|
||||
@property (nonatomic, readonly) int Id;
|
||||
@property (nonatomic, readonly) ECKeyPair *keyPair;
|
||||
@property (nonatomic, readonly, nullable) NSDate *createdAt;
|
||||
|
||||
- (instancetype)initWithId:(int)identifier keyPair:(ECKeyPair*)keyPair;
|
||||
- (instancetype)initWithId:(int)identifier
|
||||
keyPair:(ECKeyPair *)keyPair
|
||||
createdAt:(NSDate *)createdAt;
|
||||
|
||||
- (void)setCreatedAtToNow;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@ -8,8 +8,11 @@
|
||||
|
||||
#import "PreKeyRecord.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
static NSString* const kCoderPreKeyId = @"kCoderPreKeyId";
|
||||
static NSString* const kCoderPreKeyPair = @"kCoderPreKeyPair";
|
||||
static NSString* const kCoderCreatedAt = @"kCoderCreatedAt";
|
||||
|
||||
@implementation PreKeyRecord
|
||||
|
||||
@ -17,7 +20,10 @@ static NSString* const kCoderPreKeyPair = @"kCoderPreKeyPair";
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (instancetype)initWithId:(int)identifier keyPair:(ECKeyPair*)keyPair{
|
||||
- (instancetype)initWithId:(int)identifier
|
||||
keyPair:(ECKeyPair*)keyPair
|
||||
createdAt:(NSDate *)createdAt
|
||||
{
|
||||
OWSAssert(keyPair);
|
||||
|
||||
self = [super init];
|
||||
@ -25,20 +31,30 @@ static NSString* const kCoderPreKeyPair = @"kCoderPreKeyPair";
|
||||
if (self) {
|
||||
_Id = identifier;
|
||||
_keyPair = keyPair;
|
||||
_createdAt = createdAt;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)aDecoder{
|
||||
return [self initWithId:[aDecoder decodeIntForKey:kCoderPreKeyId] keyPair:[aDecoder decodeObjectOfClass:[ECKeyPair class] forKey:kCoderPreKeyPair]];
|
||||
- (nullable id)initWithCoder:(NSCoder *)aDecoder {
|
||||
return [self initWithId:[aDecoder decodeIntForKey:kCoderPreKeyId]
|
||||
keyPair:[aDecoder decodeObjectOfClass:[ECKeyPair class] forKey:kCoderPreKeyPair]
|
||||
createdAt:[aDecoder decodeObjectOfClass:[NSDate class] forKey:kCoderCreatedAt]];
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder{
|
||||
[aCoder encodeInteger:_Id forKey:kCoderPreKeyId];
|
||||
[aCoder encodeObject:_keyPair forKey:kCoderPreKeyPair];
|
||||
if (_createdAt != nil) {
|
||||
[aCoder encodeObject:_createdAt forKey:kCoderCreatedAt];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)setCreatedAtToNow {
|
||||
_createdAt = [NSDate date];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@ -6,6 +6,8 @@
|
||||
#import "PreKeyRecord.h"
|
||||
#import <Curve25519Kit/Curve25519.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface SignedPreKeyRecord : PreKeyRecord <NSSecureCoding>
|
||||
|
||||
@property (nonatomic, readonly) NSData *signature;
|
||||
@ -19,3 +21,5 @@
|
||||
- (void)markAsAcceptedByService;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@ -4,6 +4,8 @@
|
||||
|
||||
#import "SignedPrekeyRecord.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
static NSString* const kCoderPreKeyId = @"kCoderPreKeyId";
|
||||
static NSString* const kCoderPreKeyPair = @"kCoderPreKeyPair";
|
||||
static NSString* const kCoderPreKeyDate = @"kCoderPreKeyDate";
|
||||
@ -26,7 +28,9 @@ static NSString *const kCoderPreKeyWasAcceptedByService = @"kCoderPreKeyWasAccep
|
||||
OWSAssert(signature);
|
||||
OWSAssert(generatedAt);
|
||||
|
||||
self = [super initWithId:identifier keyPair:keyPair];
|
||||
self = [super initWithId:identifier
|
||||
keyPair:keyPair
|
||||
createdAt:generatedAt];
|
||||
|
||||
if (self) {
|
||||
_signature = signature;
|
||||
@ -38,7 +42,9 @@ static NSString *const kCoderPreKeyWasAcceptedByService = @"kCoderPreKeyWasAccep
|
||||
}
|
||||
|
||||
- (instancetype)initWithId:(int)identifier keyPair:(ECKeyPair *)keyPair signature:(NSData*)signature generatedAt:(NSDate *)generatedAt{
|
||||
self = [super initWithId:identifier keyPair:keyPair];
|
||||
self = [super initWithId:identifier
|
||||
keyPair:keyPair
|
||||
createdAt:generatedAt];
|
||||
|
||||
if (self) {
|
||||
_signature = signature;
|
||||
@ -48,7 +54,7 @@ static NSString *const kCoderPreKeyWasAcceptedByService = @"kCoderPreKeyWasAccep
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)aDecoder{
|
||||
- (nullable id)initWithCoder:(NSCoder *)aDecoder{
|
||||
return [self initWithId:[aDecoder decodeIntForKey:kCoderPreKeyId]
|
||||
keyPair:[aDecoder decodeObjectOfClass:[ECKeyPair class] forKey:kCoderPreKeyPair]
|
||||
signature:[aDecoder decodeObjectOfClass:[NSData class] forKey:kCoderPreKeySignature]
|
||||
@ -75,3 +81,5 @@ static NSString *const kCoderPreKeyWasAcceptedByService = @"kCoderPreKeyWasAccep
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "AxolotlStore.h"
|
||||
#import "IdentityKeyStore.h"
|
||||
#import "PreKeyStore.h"
|
||||
#import "PreKeyWhisperMessage.h"
|
||||
#import "SPKProtocolContext.h"
|
||||
#import "SessionState.h"
|
||||
#import "SessionStore.h"
|
||||
#import "SignedPreKeyStore.h"
|
||||
@ -24,20 +25,22 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
// identity and session store writes are coordinated and/or occur within a single
|
||||
// transaction.
|
||||
- (id<CipherMessage>)throws_encryptMessage:(NSData *)paddedMessage
|
||||
protocolContext:(nullable id)protocolContext NS_SWIFT_UNAVAILABLE("throws objc exceptions");
|
||||
protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext NS_SWIFT_UNAVAILABLE("throws objc exceptions");
|
||||
- (nullable id<CipherMessage>)encryptMessage:(NSData *)paddedMessage
|
||||
protocolContext:(nullable id)protocolContext
|
||||
protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext
|
||||
error:(NSError **)outError;
|
||||
|
||||
- (NSData *)throws_decrypt:(id<CipherMessage>)whisperMessage
|
||||
protocolContext:(nullable id)protocolContext NS_SWIFT_UNAVAILABLE("throws objc exceptions");
|
||||
protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext NS_SWIFT_UNAVAILABLE("throws objc exceptions");
|
||||
- (nullable NSData *)decrypt:(id<CipherMessage>)whisperMessage
|
||||
protocolContext:(nullable id)protocolContext
|
||||
protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext
|
||||
error:(NSError **)outError;
|
||||
|
||||
- (int)throws_remoteRegistrationId:(nullable id)protocolContext NS_SWIFT_UNAVAILABLE("throws objc exceptions");
|
||||
- (int)throws_remoteRegistrationId:(nullable id<SPKProtocolReadContext>)protocolContext
|
||||
NS_SWIFT_UNAVAILABLE("throws objc exceptions");
|
||||
|
||||
- (int)throws_sessionVersion:(nullable id)protocolContext NS_SWIFT_UNAVAILABLE("throws objc exceptions");
|
||||
- (int)throws_sessionVersion:(nullable id<SPKProtocolReadContext>)protocolContext
|
||||
NS_SWIFT_UNAVAILABLE("throws objc exceptions");
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SessionCipher.h"
|
||||
@ -20,6 +20,7 @@
|
||||
#import <Curve25519Kit/Ed25519.h>
|
||||
#import <HKDFKit/HKDFKit.h>
|
||||
#import <SignalCoreKit/SCKExceptionWrapper.h>
|
||||
#import <SignalCoreKit/NSData+OWS.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@ -69,6 +70,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
_deviceId = deviceId;
|
||||
_sessionStore = sessionStore;
|
||||
_identityKeyStore = identityKeyStore;
|
||||
_prekeyStore = preKeyStore;
|
||||
_sessionBuilder = [[SessionBuilder alloc] initWithSessionStore:sessionStore
|
||||
preKeyStore:preKeyStore
|
||||
signedPreKeyStore:signedPreKeyStore
|
||||
@ -81,7 +83,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
}
|
||||
|
||||
- (nullable id<CipherMessage>)encryptMessage:(NSData *)paddedMessage
|
||||
protocolContext:(nullable id)protocolContext
|
||||
protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext
|
||||
error:(NSError **)outError
|
||||
{
|
||||
__block id<CipherMessage> result;
|
||||
@ -94,7 +96,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return result;
|
||||
}
|
||||
|
||||
- (id<CipherMessage>)throws_encryptMessage:(NSData *)paddedMessage protocolContext:(nullable id)protocolContext
|
||||
- (id<CipherMessage>)throws_encryptMessage:(NSData *)paddedMessage protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext
|
||||
{
|
||||
OWSAssert(paddedMessage);
|
||||
|
||||
@ -111,7 +113,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
recipientId:self.recipientId
|
||||
direction:TSMessageDirectionOutgoing
|
||||
protocolContext:protocolContext]) {
|
||||
DDLogWarn(
|
||||
OWSLogWarn(
|
||||
@"%@ Previously known identity key for while encrypting for recipient: %@", self.tag, self.recipientId);
|
||||
@throw [NSException exceptionWithName:UntrustedIdentityKeyException
|
||||
reason:@"There is a previously known identity key."
|
||||
@ -139,7 +141,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
PendingPreKey *items = [sessionState unacknowledgedPreKeyMessageItems];
|
||||
int localRegistrationId = [sessionState localRegistrationId];
|
||||
|
||||
DDLogInfo(@"Building PreKeyWhisperMessage for: %@ with preKeyId: %d", self.recipientId, items.preKeyId);
|
||||
OWSLogInfo(@"Building PreKeyWhisperMessage for: %@.%lu with preKeyId: %d",
|
||||
self.recipientId, (unsigned long) self.deviceId, items.preKeyId);
|
||||
|
||||
cipherMessage =
|
||||
[[PreKeyWhisperMessage alloc] init_throws_withWhisperMessage:cipherMessage
|
||||
@ -160,7 +163,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
}
|
||||
|
||||
- (nullable NSData *)decrypt:(id<CipherMessage>)whisperMessage
|
||||
protocolContext:(nullable id)protocolContext
|
||||
protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext
|
||||
error:(NSError **)outError
|
||||
{
|
||||
__block NSData *_Nullable result;
|
||||
@ -173,7 +176,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSData *)throws_decrypt:(id<CipherMessage>)whisperMessage protocolContext:(nullable id)protocolContext
|
||||
- (NSData *)throws_decrypt:(id<CipherMessage>)whisperMessage protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext
|
||||
{
|
||||
OWSAssert(whisperMessage);
|
||||
|
||||
@ -198,7 +201,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
}
|
||||
|
||||
- (NSData *)throws_decryptPreKeyWhisperMessage:(PreKeyWhisperMessage *)preKeyWhisperMessage
|
||||
protocolContext:(nullable id)protocolContext
|
||||
protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext
|
||||
{
|
||||
OWSAssert(preKeyWhisperMessage);
|
||||
|
||||
@ -218,13 +221,14 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
// If there was an unsigned PreKey
|
||||
if (unsignedPreKeyId >= 0) {
|
||||
[self.prekeyStore removePreKey:unsignedPreKeyId];
|
||||
[self.prekeyStore removePreKey:unsignedPreKeyId
|
||||
protocolContext:protocolContext];
|
||||
}
|
||||
|
||||
return plaintext;
|
||||
}
|
||||
|
||||
- (NSData *)throws_decryptWhisperMessage:(WhisperMessage *)whisperMessage protocolContext:(nullable id)protocolContext
|
||||
- (NSData *)throws_decryptWhisperMessage:(WhisperMessage *)whisperMessage protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext
|
||||
{
|
||||
OWSAssert(whisperMessage);
|
||||
|
||||
@ -234,20 +238,27 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
whisperMessage:whisperMessage
|
||||
protocolContext:protocolContext];
|
||||
|
||||
if (![self.identityKeyStore isTrustedIdentityKey:sessionRecord.sessionState.remoteIdentityKey
|
||||
recipientId:self.recipientId
|
||||
direction:TSMessageDirectionIncoming
|
||||
protocolContext:protocolContext]) {
|
||||
DDLogWarn(
|
||||
@"%@ Previously known identity key for while decrypting from recipient: %@", self.tag, self.recipientId);
|
||||
@throw [NSException exceptionWithName:UntrustedIdentityKeyException
|
||||
reason:@"There is a previously known identity key."
|
||||
userInfo:@{}];
|
||||
// Our current session state may not have a remote identity key
|
||||
// if we decrypted this message using an old session. It's safe
|
||||
// to ignore this, as the identity key message was already surfaced
|
||||
// when it originally changed.
|
||||
if (sessionRecord.sessionState.remoteIdentityKey) {
|
||||
if (![self.identityKeyStore isTrustedIdentityKey:sessionRecord.sessionState.remoteIdentityKey
|
||||
recipientId:self.recipientId
|
||||
direction:TSMessageDirectionIncoming
|
||||
protocolContext:protocolContext]) {
|
||||
OWSLogWarn(
|
||||
@"%@ Previously known identity key for while decrypting from recipient: %@", self.tag, self.recipientId);
|
||||
@throw [NSException exceptionWithName:UntrustedIdentityKeyException
|
||||
reason:@"There is a previously known identity key."
|
||||
userInfo:@{}];
|
||||
}
|
||||
|
||||
[self.identityKeyStore saveRemoteIdentity:sessionRecord.sessionState.remoteIdentityKey
|
||||
recipientId:self.recipientId
|
||||
protocolContext:protocolContext];
|
||||
}
|
||||
|
||||
[self.identityKeyStore saveRemoteIdentity:sessionRecord.sessionState.remoteIdentityKey
|
||||
recipientId:self.recipientId
|
||||
protocolContext:protocolContext];
|
||||
[self.sessionStore storeSession:self.recipientId
|
||||
deviceId:self.deviceId
|
||||
session:sessionRecord
|
||||
@ -256,9 +267,14 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return plaintext;
|
||||
}
|
||||
|
||||
- (void)logDecryptionFailureForWhisperMessage:(WhisperMessage *)whisperMessage sessionState:(SessionState *)sessionState
|
||||
{
|
||||
OWSFailDebug(@"Failed to decrypt whisper message with ratchet key: %@ and counter: %d. Session loaded using recipientId: %@ and deviceId: %d. Local session has base key: %@ and counter: %d", whisperMessage.senderRatchetKey.hexadecimalString, whisperMessage.counter, self.recipientId, self.deviceId, sessionState.senderRatchetKey.hexadecimalString, sessionState.previousCounter);
|
||||
}
|
||||
|
||||
- (NSData *)throws_decryptWithSessionRecord:(SessionRecord *)sessionRecord
|
||||
whisperMessage:(WhisperMessage *)whisperMessage
|
||||
protocolContext:(nullable id)protocolContext
|
||||
protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext
|
||||
{
|
||||
OWSAssert(sessionRecord);
|
||||
OWSAssert(whisperMessage);
|
||||
@ -270,51 +286,49 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
NSData *decryptedData = [self throws_decryptWithSessionState:sessionState
|
||||
whisperMessage:whisperMessage
|
||||
protocolContext:protocolContext];
|
||||
DDLogDebug(@"%@ successfully decrypted with current session state: %@", self.tag, sessionState);
|
||||
OWSLogDebug(@"%@ successfully decrypted with current session state: %@", self.tag, sessionState);
|
||||
return decryptedData;
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
if ([exception.name isEqualToString:InvalidMessageException]) {
|
||||
[exceptions addObject:exception];
|
||||
} else {
|
||||
[self logDecryptionFailureForWhisperMessage:whisperMessage sessionState:sessionState];
|
||||
@throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
// If we can decrypt the message with an "old" session state, that means the sender is using an "old" session.
|
||||
// In which case, we promote that session to "active" so as to converge on a single session for sending/receiving.
|
||||
__block NSUInteger stateToPromoteIdx;
|
||||
__block NSData *decryptedData;
|
||||
// We can continue to receive messages from this sender, but we will send to them using our current session.
|
||||
__block NSData *_Nullable decryptedData;
|
||||
[[sessionRecord previousSessionStates]
|
||||
enumerateObjectsUsingBlock:^(SessionState *_Nonnull previousState, NSUInteger idx, BOOL *_Nonnull stop) {
|
||||
@try {
|
||||
decryptedData = [self throws_decryptWithSessionState:previousState
|
||||
whisperMessage:whisperMessage
|
||||
protocolContext:protocolContext];
|
||||
DDLogInfo(@"%@ successfully decrypted with PREVIOUS session state: %@", self.tag, previousState);
|
||||
OWSLogInfo(@"%@ successfully decrypted with PREVIOUS session state: %@", self.tag, previousState);
|
||||
OWSAssert(decryptedData != nil);
|
||||
stateToPromoteIdx = idx;
|
||||
*stop = YES;
|
||||
} @catch (NSException *exception) {
|
||||
if (![exception.name isEqualToString:InvalidMessageException]) {
|
||||
[self logDecryptionFailureForWhisperMessage:whisperMessage sessionState:sessionState];
|
||||
}
|
||||
|
||||
[exceptions addObject:exception];
|
||||
}
|
||||
}];
|
||||
|
||||
if (decryptedData) {
|
||||
SessionState *sessionStateToPromote = [sessionRecord previousSessionStates][stateToPromoteIdx];
|
||||
OWSAssert(sessionStateToPromote != nil);
|
||||
DDLogInfo(@"%@ promoting session: %@", self.tag, sessionStateToPromote);
|
||||
[[sessionRecord previousSessionStates] removeObjectAtIndex:stateToPromoteIdx];
|
||||
[sessionRecord promoteState:sessionStateToPromote];
|
||||
|
||||
return decryptedData;
|
||||
}
|
||||
|
||||
BOOL containsActiveSession =
|
||||
[self.sessionStore containsSession:self.recipientId deviceId:self.deviceId protocolContext:protocolContext];
|
||||
DDLogError(@"%@ No valid session for recipient: %@ containsActiveSession: %@, previousStates: %lu",
|
||||
OWSLogError(@"%@ No valid session for recipient: %@.%lu containsActiveSession: %@, previousStates: %lu",
|
||||
self.tag,
|
||||
self.recipientId,
|
||||
(unsigned long) self.deviceId,
|
||||
(containsActiveSession ? @"YES" : @"NO"),
|
||||
(unsigned long)sessionRecord.previousSessionStates.count);
|
||||
|
||||
@ -334,7 +348,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
- (NSData *)throws_decryptWithSessionState:(SessionState *)sessionState
|
||||
whisperMessage:(WhisperMessage *)whisperMessage
|
||||
protocolContext:(nullable id)protocolContext
|
||||
protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext
|
||||
{
|
||||
OWSAssert(sessionState);
|
||||
OWSAssert(whisperMessage);
|
||||
@ -383,10 +397,10 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@try {
|
||||
if ([sessionState hasReceiverChain:theirEphemeral]) {
|
||||
DDLogInfo(@"%@ %@.%d has existing receiver chain.", self.tag, self.recipientId, self.deviceId);
|
||||
OWSLogInfo(@"%@ %@.%d has existing receiver chain.", self.tag, self.recipientId, self.deviceId);
|
||||
return [sessionState receiverChainKey:theirEphemeral];
|
||||
} else{
|
||||
DDLogInfo(@"%@ %@.%d creating new chains.", self.tag, self.recipientId, self.deviceId);
|
||||
OWSLogInfo(@"%@ %@.%d creating new chains.", self.tag, self.recipientId, self.deviceId);
|
||||
RootKey *rootKey = [sessionState rootKey];
|
||||
OWSAssert(rootKey.keyData.length == 32);
|
||||
|
||||
@ -442,7 +456,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
}
|
||||
}
|
||||
|
||||
NSUInteger kCounterLimit = 2000;
|
||||
NSUInteger kCounterLimit = 25000;
|
||||
int counterOffset;
|
||||
if (__builtin_sub_overflow(counter, chainKey.index, &counterOffset)) {
|
||||
OWSFailDebug(@"Overflow while calculating counter offset");
|
||||
@ -484,7 +498,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return versionByte;
|
||||
}
|
||||
|
||||
- (int)throws_remoteRegistrationId:(nullable id)protocolContext
|
||||
- (int)throws_remoteRegistrationId:(nullable id<SPKProtocolReadContext>)protocolContext
|
||||
{
|
||||
SessionRecord *_Nullable record =
|
||||
[self.sessionStore loadSession:self.recipientId deviceId:_deviceId protocolContext:protocolContext];
|
||||
@ -496,7 +510,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return record.sessionState.remoteRegistrationId;
|
||||
}
|
||||
|
||||
- (int)throws_sessionVersion:(nullable id)protocolContext
|
||||
- (int)throws_sessionVersion:(nullable id<SPKProtocolReadContext>)protocolContext
|
||||
{
|
||||
SessionRecord *_Nullable record =
|
||||
[self.sessionStore loadSession:self.recipientId deviceId:_deviceId protocolContext:protocolContext];
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "AxolotlStore.h"
|
||||
#import "IdentityKeyStore.h"
|
||||
#import "PreKeyBundle.h"
|
||||
#import "PreKeyStore.h"
|
||||
#import "SPKProtocolContext.h"
|
||||
#import "SessionStore.h"
|
||||
#import "SignedPreKeyStore.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
@ -30,14 +31,14 @@ extern const int kPreKeyOfLastResortId;
|
||||
deviceId:(int)deviceId;
|
||||
|
||||
- (void)throws_processPrekeyBundle:(PreKeyBundle *)preKeyBundle
|
||||
protocolContext:(nullable id)protocolContext NS_SWIFT_UNAVAILABLE("throws objc exceptions");
|
||||
protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext NS_SWIFT_UNAVAILABLE("throws objc exceptions");
|
||||
- (BOOL)processPrekeyBundle:(PreKeyBundle *)preKeyBundle
|
||||
protocolContext:(nullable id)protocolContext
|
||||
protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext
|
||||
error:(NSError **)outError;
|
||||
|
||||
- (int)throws_processPrekeyWhisperMessage:(PreKeyWhisperMessage *)message
|
||||
withSession:(SessionRecord *)sessionRecord
|
||||
protocolContext:(nullable id)protocolContext NS_SWIFT_UNAVAILABLE("throws objc exceptions");
|
||||
protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext NS_SWIFT_UNAVAILABLE("throws objc exceptions");
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SessionBuilder.h"
|
||||
@ -80,7 +80,7 @@ const int kPreKeyOfLastResortId = 0xFFFFFF;
|
||||
}
|
||||
|
||||
- (BOOL)processPrekeyBundle:(PreKeyBundle *)preKeyBundle
|
||||
protocolContext:(nullable id)protocolContext
|
||||
protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext
|
||||
error:(NSError **)outError
|
||||
{
|
||||
return [SCKExceptionWrapper
|
||||
@ -90,7 +90,7 @@ const int kPreKeyOfLastResortId = 0xFFFFFF;
|
||||
error:outError];
|
||||
}
|
||||
|
||||
- (void)throws_processPrekeyBundle:(PreKeyBundle *)preKeyBundle protocolContext:(nullable id)protocolContext
|
||||
- (void)throws_processPrekeyBundle:(PreKeyBundle *)preKeyBundle protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext
|
||||
{
|
||||
OWSAssert(preKeyBundle);
|
||||
|
||||
@ -146,12 +146,6 @@ const int kPreKeyOfLastResortId = 0xFFFFFF;
|
||||
BOOL previousIdentityExisted = [self.identityStore saveRemoteIdentity:theirIdentityKey
|
||||
recipientId:self.recipientId
|
||||
protocolContext:protocolContext];
|
||||
if (previousIdentityExisted) {
|
||||
DDLogInfo(@"%@ PKBundle removing previous session states for changed identity for recipient:%@",
|
||||
self.tag,
|
||||
self.recipientId);
|
||||
[sessionRecord removePreviousSessionStates];
|
||||
}
|
||||
|
||||
[self.sessionStore storeSession:self.recipientId
|
||||
deviceId:self.deviceId
|
||||
@ -161,7 +155,7 @@ const int kPreKeyOfLastResortId = 0xFFFFFF;
|
||||
|
||||
- (int)throws_processPrekeyWhisperMessage:(PreKeyWhisperMessage *)message
|
||||
withSession:(SessionRecord *)sessionRecord
|
||||
protocolContext:(nullable id)protocolContext
|
||||
protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext
|
||||
{
|
||||
OWSAssert(message);
|
||||
OWSAssert(sessionRecord);
|
||||
@ -197,7 +191,7 @@ const int kPreKeyOfLastResortId = 0xFFFFFF;
|
||||
|
||||
- (int)throws_processPrekeyV3:(PreKeyWhisperMessage *)message
|
||||
withSession:(SessionRecord *)sessionRecord
|
||||
protocolContext:(nullable id)protocolContext
|
||||
protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext
|
||||
{
|
||||
OWSAssert(message);
|
||||
OWSAssert(sessionRecord);
|
||||
@ -208,11 +202,28 @@ const int kPreKeyOfLastResortId = 0xFFFFFF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ECKeyPair *ourSignedPrekey = [self.signedPreKeyStore throws_loadSignedPrekey:message.signedPrekeyId].keyPair;
|
||||
SignedPreKeyRecord *_Nullable signedPreKeyRecord = [self.signedPreKeyStore loadSignedPreKey:message.signedPrekeyId
|
||||
protocolContext:protocolContext];
|
||||
if (signedPreKeyRecord == nil) {
|
||||
OWSLogWarn(@"Signed prekey id: %lu, prekey id: %lu.",
|
||||
(unsigned long) message.signedPrekeyId,
|
||||
(unsigned long) message.prekeyID);
|
||||
OWSLogWarn(@"Available signed prekey ids: %@",
|
||||
[self.signedPreKeyStore availableSignedPreKeyIdsWithProtocolContext:protocolContext]);
|
||||
|
||||
OWSRaiseException(InvalidKeyIdException, @"No signed prekey found matching key id");
|
||||
}
|
||||
ECKeyPair *ourSignedPrekey = signedPreKeyRecord.keyPair;
|
||||
|
||||
ECKeyPair *_Nullable ourOneTimePreKey;
|
||||
if (message.prekeyID >= 0) {
|
||||
ourOneTimePreKey = [self.prekeyStore throws_loadPreKey:message.prekeyID].keyPair;
|
||||
PreKeyRecord *_Nullable preKey = [self.prekeyStore loadPreKey:message.prekeyID
|
||||
protocolContext:protocolContext];
|
||||
if (preKey == nil) {
|
||||
OWSFailDebug(@"Missing prekeyID: %lu", (unsigned long) message.prekeyID);
|
||||
OWSRaiseException(InvalidKeyIdException, @"No pre key found matching key id");
|
||||
}
|
||||
ourOneTimePreKey = preKey.keyPair;
|
||||
} else {
|
||||
DDLogWarn(@"%@ Processing PreKey message which had no one-time prekey.", self.tag);
|
||||
}
|
||||
|
||||
@ -11,13 +11,11 @@
|
||||
|
||||
- (BOOL)hasSessionState:(int)version baseKey:(NSData*)aliceBaseKey;
|
||||
- (SessionState*)sessionState;
|
||||
- (NSMutableArray<SessionState *> *)previousSessionStates;
|
||||
- (NSArray<SessionState *> *)previousSessionStates;
|
||||
|
||||
- (void)removePreviousSessionStates;
|
||||
- (BOOL)isFresh;
|
||||
- (void)markAsUnFresh;
|
||||
- (void)archiveCurrentState;
|
||||
- (void)promoteState:(SessionState*)promotedState;
|
||||
- (void)setState:(SessionState*)sessionState;
|
||||
|
||||
@end
|
||||
|
||||
@ -71,16 +71,11 @@
|
||||
return _sessionState;
|
||||
}
|
||||
|
||||
- (NSMutableArray<SessionState *> *)previousSessionStates
|
||||
- (NSArray<SessionState *> *)previousSessionStates
|
||||
{
|
||||
return _previousStates;
|
||||
}
|
||||
|
||||
- (void)removePreviousSessionStates
|
||||
{
|
||||
[_previousStates removeAllObjects];
|
||||
}
|
||||
|
||||
- (BOOL)isFresh{
|
||||
return _fresh;
|
||||
}
|
||||
@ -91,6 +86,10 @@
|
||||
}
|
||||
|
||||
- (void)archiveCurrentState{
|
||||
if (self.sessionState.isFresh) {
|
||||
OWSLogInfo(@"Skipping archive, current session state is fresh.");
|
||||
return;
|
||||
}
|
||||
[self promoteState:[SessionState new]];
|
||||
}
|
||||
|
||||
@ -103,7 +102,7 @@
|
||||
ows_sub_overflow(self.previousStates.count, ARCHIVED_STATES_MAX_LENGTH, &deleteCount);
|
||||
NSIndexSet *indexesToDelete =
|
||||
[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(ARCHIVED_STATES_MAX_LENGTH, deleteCount)];
|
||||
[self.previousSessionStates removeObjectsAtIndexes:indexesToDelete];
|
||||
[self.previousStates removeObjectsAtIndexes:indexesToDelete];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -39,6 +39,8 @@
|
||||
@property(nonatomic)int remoteRegistrationId;
|
||||
@property(nonatomic)int localRegistrationId;
|
||||
|
||||
@property (nonatomic, readonly) BOOL isFresh;
|
||||
|
||||
- (NSData*)senderRatchetKey;
|
||||
- (ECKeyPair*)senderRatchetKeyPair;
|
||||
|
||||
|
||||
@ -119,6 +119,11 @@ static NSString* const kCoderPendingPrekey = @"kCoderPendingPrekey";
|
||||
[aCoder encodeObject:self.pendingPreKey forKey:kCoderPendingPrekey];
|
||||
}
|
||||
|
||||
- (BOOL)isFresh
|
||||
{
|
||||
return self.remoteIdentityKey == nil && self.localIdentityKey == nil && self.sendingChain == nil && self.receivingChains.count == 0 && self.pendingPreKey == nil;
|
||||
}
|
||||
|
||||
- (NSData*)senderRatchetKey{
|
||||
return [[self senderRatchetKeyPair] publicKey];
|
||||
}
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SPKProtocolContext.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
@ -17,9 +18,9 @@ typedef NS_ENUM(NSInteger, TSMessageDirection) {
|
||||
// See a discussion of the protocolContext in SessionCipher.h.
|
||||
@protocol IdentityKeyStore <NSObject>
|
||||
|
||||
- (nullable ECKeyPair *)identityKeyPair:(nullable id)protocolContext;
|
||||
- (nullable ECKeyPair *)identityKeyPair:(nullable id<SPKProtocolWriteContext>)protocolContext;
|
||||
|
||||
- (int)localRegistrationId:(nullable id)protocolContext;
|
||||
- (int)localRegistrationId:(nullable id<SPKProtocolWriteContext>)protocolContext;
|
||||
|
||||
/**
|
||||
* Record a recipients identity key
|
||||
@ -32,7 +33,7 @@ typedef NS_ENUM(NSInteger, TSMessageDirection) {
|
||||
*/
|
||||
- (BOOL)saveRemoteIdentity:(NSData *)identityKey
|
||||
recipientId:(NSString *)recipientId
|
||||
protocolContext:(nullable id)protocolContext;
|
||||
protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext;
|
||||
|
||||
/**
|
||||
* @param identityKey key data used to identify the recipient
|
||||
@ -46,11 +47,12 @@ typedef NS_ENUM(NSInteger, TSMessageDirection) {
|
||||
- (BOOL)isTrustedIdentityKey:(NSData *)identityKey
|
||||
recipientId:(NSString *)recipientId
|
||||
direction:(TSMessageDirection)direction
|
||||
protocolContext:(nullable id)protocolContext;
|
||||
protocolContext:(nullable id<SPKProtocolReadContext>)protocolContext;
|
||||
|
||||
- (nullable NSData *)identityKeyForRecipientId:(NSString *)recipientId;
|
||||
|
||||
- (nullable NSData *)identityKeyForRecipientId:(NSString *)recipientId protocolContext:(nullable id)protocolContext;
|
||||
- (nullable NSData *)identityKeyForRecipientId:(NSString *)recipientId
|
||||
protocolContext:(nullable id<SPKProtocolReadContext>)protocolContext;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "PreKeyRecord.h"
|
||||
@ -9,13 +9,14 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol PreKeyStore <NSObject>
|
||||
|
||||
- (PreKeyRecord *)throws_loadPreKey:(int)preKeyId NS_SWIFT_UNAVAILABLE("throws objc exceptions");
|
||||
- (nullable PreKeyRecord *)loadPreKey:(int)preKeyId
|
||||
protocolContext:(nullable id<SPKProtocolReadContext>)protocolContext;
|
||||
|
||||
- (void)storePreKey:(int)preKeyId preKeyRecord:(PreKeyRecord *)record;
|
||||
- (void)storePreKey:(int)preKeyId preKeyRecord:(PreKeyRecord *)record
|
||||
protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext;
|
||||
|
||||
- (BOOL)containsPreKey:(int)preKeyId;
|
||||
|
||||
- (void)removePreKey:(int)preKeyId;
|
||||
- (void)removePreKey:(int)preKeyId
|
||||
protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SPKProtocolContext.h"
|
||||
#import "SessionRecord.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@ -20,24 +21,24 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*/
|
||||
- (SessionRecord *)loadSession:(NSString *)contactIdentifier
|
||||
deviceId:(int)deviceId
|
||||
protocolContext:(nullable id)protocolContext;
|
||||
protocolContext:(nullable id<SPKProtocolReadContext>)protocolContext;
|
||||
|
||||
- (NSArray *)subDevicesSessions:(NSString *)contactIdentifier protocolContext:(nullable id)protocolContext __attribute__((deprecated));
|
||||
- (NSArray *)subDevicesSessions:(NSString *)contactIdentifier protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext __attribute__((deprecated));
|
||||
|
||||
- (void)storeSession:(NSString *)contactIdentifier
|
||||
deviceId:(int)deviceId
|
||||
session:(SessionRecord *)session
|
||||
protocolContext:(nullable id)protocolContext;
|
||||
protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext;
|
||||
|
||||
- (BOOL)containsSession:(NSString *)contactIdentifier
|
||||
deviceId:(int)deviceId
|
||||
protocolContext:(nullable id)protocolContext;
|
||||
protocolContext:(nullable id<SPKProtocolReadContext>)protocolContext;
|
||||
|
||||
- (void)deleteSessionForContact:(NSString *)contactIdentifier
|
||||
deviceId:(int)deviceId
|
||||
protocolContext:(nullable id)protocolContext;
|
||||
protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext;
|
||||
|
||||
- (void)deleteAllSessionsForContact:(NSString *)contactIdentifier protocolContext:(nullable id)protocolContext;
|
||||
- (void)deleteAllSessionsForContact:(NSString *)contactIdentifier protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SignedPrekeyRecord.h"
|
||||
@ -9,17 +9,22 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol SignedPreKeyStore <NSObject>
|
||||
|
||||
- (SignedPreKeyRecord *)throws_loadSignedPrekey:(int)signedPreKeyId NS_SWIFT_UNAVAILABLE("throws objc exceptions");
|
||||
- (nullable SignedPreKeyRecord *)loadSignedPreKey:(int)signedPreKeyId
|
||||
protocolContext:(nullable id<SPKProtocolReadContext>)protocolContext;
|
||||
|
||||
- (nullable SignedPreKeyRecord *)loadSignedPrekeyOrNil:(int)signedPreKeyId;
|
||||
- (NSArray<SignedPreKeyRecord *> *)loadSignedPreKeysWithProtocolContext:(nullable id<SPKProtocolReadContext>)protocolContext;
|
||||
|
||||
- (NSArray<SignedPreKeyRecord *> *)loadSignedPreKeys;
|
||||
- (void)storeSignedPreKey:(int)signedPreKeyId
|
||||
signedPreKeyRecord:(SignedPreKeyRecord *)signedPreKeyRecord
|
||||
protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext;
|
||||
|
||||
- (void)storeSignedPreKey:(int)signedPreKeyId signedPreKeyRecord:(SignedPreKeyRecord *)signedPreKeyRecord;
|
||||
- (BOOL)containsSignedPreKey:(int)signedPreKeyId
|
||||
protocolContext:(nullable id<SPKProtocolReadContext>)protocolContext;
|
||||
|
||||
- (BOOL)containsSignedPreKey:(int)signedPreKeyId;
|
||||
- (void)removeSignedPreKey:(int)signedPreKeyId
|
||||
protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext;
|
||||
|
||||
- (void)removeSignedPreKey:(int)signedPrekeyId;
|
||||
- (NSArray<NSString *> *)availableSignedPreKeyIdsWithProtocolContext:(nullable id<SPKProtocolReadContext>)protocolContext;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SPKMockProtocolStore.h"
|
||||
@ -52,31 +52,13 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
#pragma mark Signed PreKey Store
|
||||
|
||||
- (SignedPreKeyRecord *)throws_loadSignedPrekey:(int)signedPreKeyId
|
||||
- (nullable SignedPreKeyRecord *)loadSignedPreKey:(int)signedPreKeyId
|
||||
protocolContext:(nullable id<SPKProtocolReadContext>)protocolContext
|
||||
{
|
||||
if (![[self.signedPreKeyStore allKeys] containsObject:[NSNumber numberWithInt:signedPreKeyId]]) {
|
||||
@throw [NSException exceptionWithName:InvalidKeyIdException reason:@"No such signedprekeyrecord" userInfo:nil];
|
||||
}
|
||||
|
||||
return [self.signedPreKeyStore objectForKey:[NSNumber numberWithInt:signedPreKeyId]];
|
||||
}
|
||||
|
||||
- (nullable SignedPreKeyRecord *)loadSignedPrekeyOrNil:(int)signedPreKeyId
|
||||
{
|
||||
if ([self containsSignedPreKey:signedPreKeyId]) {
|
||||
@try {
|
||||
// Given that we've checked for `contains` this really shouldn't fail.
|
||||
return [self throws_loadSignedPrekey:signedPreKeyId];
|
||||
} @catch (NSException *exception) {
|
||||
OWSFailDebug(@"unexpected exception: %@", exception);
|
||||
return nil;
|
||||
}
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray<SignedPreKeyRecord *> *)loadSignedPreKeys
|
||||
- (NSArray<SignedPreKeyRecord *> *)loadSignedPreKeysWithProtocolContext:(nullable id<SPKProtocolReadContext>)protocolContext
|
||||
{
|
||||
NSMutableArray *results = [NSMutableArray array];
|
||||
|
||||
@ -87,12 +69,20 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return results;
|
||||
}
|
||||
|
||||
- (void)storeSignedPreKey:(int)signedPreKeyId signedPreKeyRecord:(SignedPreKeyRecord *)signedPreKeyRecord
|
||||
- (NSArray<NSString *> *)availableSignedPreKeyIdsWithProtocolContext:(nullable id<SPKProtocolReadContext>)protocolContext
|
||||
{
|
||||
return @[];
|
||||
}
|
||||
|
||||
- (void)storeSignedPreKey:(int)signedPreKeyId
|
||||
signedPreKeyRecord:(SignedPreKeyRecord *)signedPreKeyRecord
|
||||
protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext
|
||||
{
|
||||
[self.signedPreKeyStore setObject:signedPreKeyRecord forKey:[NSNumber numberWithInteger:signedPreKeyId]];
|
||||
}
|
||||
|
||||
- (BOOL)containsSignedPreKey:(int)signedPreKeyId
|
||||
protocolContext:(nullable id<SPKProtocolReadContext>)protocolContext
|
||||
{
|
||||
if ([[self.signedPreKeyStore allKeys] containsObject:[NSNumber numberWithInteger:signedPreKeyId]]) {
|
||||
return TRUE;
|
||||
@ -101,19 +91,17 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
- (void)removeSignedPreKey:(int)signedPrekeyId
|
||||
- (void)removeSignedPreKey:(int)signedPreKeyId
|
||||
protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext
|
||||
{
|
||||
[self.signedPreKeyStore removeObjectForKey:[NSNumber numberWithInteger:signedPrekeyId]];
|
||||
[self.signedPreKeyStore removeObjectForKey:[NSNumber numberWithInteger:signedPreKeyId]];
|
||||
}
|
||||
|
||||
#pragma mark PreKey Store
|
||||
|
||||
- (PreKeyRecord *)throws_loadPreKey:(int)preKeyId
|
||||
- (nullable PreKeyRecord *)loadPreKey:(int)preKeyId
|
||||
protocolContext:(nullable id<SPKProtocolReadContext>)protocolContext;
|
||||
{
|
||||
if (![[self.preKeyStore allKeys] containsObject:[NSNumber numberWithInt:preKeyId]]) {
|
||||
@throw [NSException exceptionWithName:InvalidKeyIdException reason:@"No such signedprekeyrecord" userInfo:nil];
|
||||
}
|
||||
|
||||
return [self.preKeyStore objectForKey:[NSNumber numberWithInt:preKeyId]];
|
||||
}
|
||||
|
||||
@ -129,39 +117,32 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
}
|
||||
|
||||
- (void)storePreKey:(int)preKeyId preKeyRecord:(PreKeyRecord *)record
|
||||
protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext
|
||||
{
|
||||
[self.preKeyStore setObject:record forKey:[NSNumber numberWithInt:preKeyId]];
|
||||
}
|
||||
|
||||
- (BOOL)containsPreKey:(int)preKeyId
|
||||
{
|
||||
if ([[self.preKeyStore allKeys] containsObject:[NSNumber numberWithInteger:preKeyId]]) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
- (void)removePreKey:(int)preKeyId
|
||||
protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext
|
||||
{
|
||||
[self.preKeyStore removeObjectForKey:[NSNumber numberWithInt:preKeyId]];
|
||||
}
|
||||
|
||||
#pragma mark IdentityKeyStore
|
||||
|
||||
- (nullable ECKeyPair *)identityKeyPair:(nullable id)protocolContext
|
||||
- (nullable ECKeyPair *)identityKeyPair:(nullable id<SPKProtocolWriteContext>)protocolContext
|
||||
{
|
||||
return self.identityKeyPair;
|
||||
}
|
||||
|
||||
- (int)localRegistrationId:(nullable id)protocolContext
|
||||
- (int)localRegistrationId:(nullable id<SPKProtocolWriteContext>)protocolContext
|
||||
{
|
||||
return self.localRegistrationId;
|
||||
}
|
||||
|
||||
- (BOOL)saveRemoteIdentity:(NSData *)identityKey
|
||||
recipientId:(NSString *)recipientId
|
||||
protocolContext:(nullable id)protocolContext
|
||||
protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext
|
||||
{
|
||||
NSData *existingKey = [self.trustedKeys objectForKey:recipientId];
|
||||
|
||||
@ -176,7 +157,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (BOOL)isTrustedIdentityKey:(NSData *)identityKey
|
||||
recipientId:(NSString *)recipientId
|
||||
direction:(TSMessageDirection)direction
|
||||
protocolContext:(nullable id)protocolContext
|
||||
protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext
|
||||
{
|
||||
NSData *data = [self.trustedKeys objectForKey:recipientId];
|
||||
if (!data) {
|
||||
@ -202,7 +183,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return [self identityKeyForRecipientId:recipientId protocolContext:nil];
|
||||
}
|
||||
|
||||
- (nullable NSData *)identityKeyForRecipientId:(NSString *)recipientId protocolContext:(nullable id)protocolContext
|
||||
- (nullable NSData *)identityKeyForRecipientId:(NSString *)recipientId
|
||||
protocolContext:(nullable id<SPKProtocolReadContext>)protocolContext
|
||||
{
|
||||
NSData *_Nullable data = [self.trustedKeys objectForKey:recipientId];
|
||||
return data;
|
||||
@ -212,7 +194,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
- (SessionRecord *)loadSession:(NSString *)contactIdentifier
|
||||
deviceId:(int)deviceId
|
||||
protocolContext:(nullable id)protocolContext
|
||||
protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext
|
||||
{
|
||||
SessionRecord *sessionRecord = [[self deviceSessionRecordsForContactIdentifier:contactIdentifier]
|
||||
objectForKey:[NSNumber numberWithInteger:deviceId]];
|
||||
@ -224,10 +206,13 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return sessionRecord;
|
||||
}
|
||||
|
||||
- (NSArray *)subDevicesSessions:(NSString *)contactIdentifier protocolContext:(nullable id)protocolContext
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
|
||||
- (NSArray *)subDevicesSessions:(NSString *)contactIdentifier protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext
|
||||
{
|
||||
return [[self deviceSessionRecordsForContactIdentifier:contactIdentifier] allKeys];
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
- (NSMutableDictionary *)deviceSessionRecordsForContactIdentifier:(NSString *)contactIdentifier
|
||||
{
|
||||
@ -237,7 +222,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (void)storeSession:(NSString *)contactIdentifier
|
||||
deviceId:(int)deviceId
|
||||
session:(SessionRecord *)session
|
||||
protocolContext:(nullable id)protocolContext
|
||||
protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext
|
||||
{
|
||||
NSAssert(session, @"Session can't be nil");
|
||||
NSMutableDictionary *deviceSessions = self.sessionRecords[contactIdentifier];
|
||||
@ -251,7 +236,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
- (BOOL)containsSession:(NSString *)contactIdentifier
|
||||
deviceId:(int)deviceId
|
||||
protocolContext:(nullable id)protocolContext
|
||||
protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext
|
||||
{
|
||||
|
||||
if ([[self.sessionRecords objectForKey:contactIdentifier] objectForKey:[NSNumber numberWithInt:deviceId]]) {
|
||||
@ -262,14 +247,14 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
- (void)deleteSessionForContact:(NSString *)contactIdentifier
|
||||
deviceId:(int)deviceId
|
||||
protocolContext:(nullable id)protocolContext
|
||||
protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext
|
||||
{
|
||||
NSMutableDictionary<NSNumber *, SessionRecord *> *sessions =
|
||||
[self deviceSessionRecordsForContactIdentifier:contactIdentifier];
|
||||
[sessions removeObjectForKey:@(deviceId)];
|
||||
}
|
||||
|
||||
- (void)deleteAllSessionsForContact:(NSString *)contactIdentifier protocolContext:(nullable id)protocolContext
|
||||
- (void)deleteAllSessionsForContact:(NSString *)contactIdentifier protocolContext:(nullable id<SPKProtocolWriteContext>)protocolContext
|
||||
{
|
||||
[self.sessionRecords removeObjectForKey:contactIdentifier];
|
||||
}
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSData (keyVersionByte)
|
||||
|
||||
- (instancetype)prependKeyType;
|
||||
@ -12,3 +14,5 @@
|
||||
- (nullable instancetype)removeKeyTypeAndReturnError:(NSError **)outError;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSData+keyVersionByte.h"
|
||||
#import "AxolotlExceptions.h"
|
||||
#import <SignalCoreKit/SCKExceptionWrapper.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@implementation NSData (keyVersionByte)
|
||||
|
||||
const Byte DJB_TYPE = 0x05;
|
||||
@ -46,3 +48,5 @@ const Byte DJB_TYPE = 0x05;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
17
AxolotlKit/Classes/Utility/SPKProtocolContext.h
Normal file
17
AxolotlKit/Classes/Utility/SPKProtocolContext.h
Normal file
@ -0,0 +1,17 @@
|
||||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol SPKProtocolReadContext <NSObject>
|
||||
|
||||
@end
|
||||
|
||||
@protocol SPKProtocolWriteContext <SPKProtocolReadContext>
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@ -80,8 +80,16 @@
|
||||
XCTAssert([outgoingMessage isKindOfClass:[PreKeyWhisperMessage class]], @"Message should be PreKey type");
|
||||
|
||||
PreKeyWhisperMessage *incomingMessage = (PreKeyWhisperMessage*)outgoingMessage;
|
||||
[bobStore storePreKey:31337 preKeyRecord:[[PreKeyRecord alloc] initWithId:bobPreKey.preKeyId keyPair:bobPreKeyPair]];
|
||||
[bobStore storeSignedPreKey:22 signedPreKeyRecord:[[SignedPreKeyRecord alloc] initWithId:22 keyPair:bobSignedPreKeyPair signature:bobSignedPreKeySignature generatedAt:[NSDate date]]];
|
||||
[bobStore storePreKey:31337 preKeyRecord:[[PreKeyRecord alloc] initWithId:bobPreKey.preKeyId
|
||||
keyPair:bobPreKeyPair
|
||||
createdAt:[NSDate date]]
|
||||
protocolContext:nil];
|
||||
[bobStore storeSignedPreKey:22
|
||||
signedPreKeyRecord:[[SignedPreKeyRecord alloc] initWithId:22
|
||||
keyPair:bobSignedPreKeyPair
|
||||
signature:bobSignedPreKeySignature
|
||||
generatedAt:[NSDate date]]
|
||||
protocolContext:nil];
|
||||
|
||||
SessionCipher *bobSessionCipher = [[SessionCipher alloc] initWithAxolotlStore:bobStore recipientId:ALICE_RECIPIENT_ID deviceId:1];
|
||||
[bobSessionCipher throws_decrypt:incomingMessage protocolContext:nil];
|
||||
@ -89,7 +97,7 @@
|
||||
XCTAssert([bobStore containsSession:ALICE_RECIPIENT_ID deviceId:1 protocolContext:nil]);
|
||||
XCTAssert([bobStore loadSession:ALICE_RECIPIENT_ID deviceId:1 protocolContext:nil].sessionState.version == 3);
|
||||
XCTAssert([bobStore loadSession:ALICE_RECIPIENT_ID deviceId:1 protocolContext:nil].sessionState.aliceBaseKey != nil);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the case where an attacker would send a new PreKeyWhisperMessage with another IdentityKey
|
||||
|
||||
@ -13,6 +13,10 @@
|
||||
#import <Curve25519Kit/Curve25519.h>
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
@interface SessionRecord (Private)
|
||||
- (void)promoteState:(SessionState *)promotedState;
|
||||
@end
|
||||
|
||||
@interface SessionCipherTest : XCTestCase
|
||||
|
||||
@property (nonatomic, readonly) NSString *aliceIdentifier;
|
||||
@ -77,10 +81,11 @@
|
||||
XCTAssertNotEqualObjects(initialSessionState, activeSession.sessionState);
|
||||
XCTAssertEqualObjects(newSessionState, activeSession.sessionState);
|
||||
|
||||
// 3.) Bob should promote back the initial session after receiving a message from that old session.
|
||||
// 3.) Bob should decrypt with initial session after receiving a message from that old session,
|
||||
// but importantly *not* promote it to be the active session.
|
||||
[self runInteractionWithAliceRecord:aliceSessionRecord bobRecord:bobSessionRecord];
|
||||
XCTAssertNotEqualObjects(newSessionState, activeSession.sessionState);
|
||||
XCTAssertEqualObjects(initialSessionState, activeSession.sessionState);
|
||||
XCTAssertNotEqualObjects(initialSessionState, activeSession.sessionState);
|
||||
XCTAssertEqualObjects(newSessionState, activeSession.sessionState);
|
||||
XCTAssertEqual(1, bobSessionRecord.previousSessionStates.count);
|
||||
XCTAssertEqual(0, aliceSessionRecord.previousSessionStates.count);
|
||||
}
|
||||
|
||||
@ -7,14 +7,6 @@
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface ECKeyPair (ECKeyPairTestingPrivate)
|
||||
|
||||
- (nullable id)initWithPublicKey:(NSData *)publicKey privateKey:(NSData *)privateKey;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation ECKeyPair (testing)
|
||||
|
||||
+ (ECKeyPair *)throws_keyPairWithPrivateKey:(NSData *)privateKey publicKey:(NSData *)publicKey
|
||||
@ -27,7 +19,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Public or Private key is not required size" userInfo:@{@"PrivateKey":privateKey, @"Public Key":publicKey}];
|
||||
}
|
||||
|
||||
ECKeyPair *keyPairCopy = [[ECKeyPair alloc] initWithPublicKey:[publicKey copy] privateKey:[privateKey copy]];
|
||||
NSError *error;
|
||||
ECKeyPair *_Nullable keyPairCopy = [[ECKeyPair alloc] initWithPublicKeyData:[publicKey copy] privateKeyData:[privateKey copy] error:&error];
|
||||
OWSAssertDebug(error == nil && keyPairCopy != nil);
|
||||
return keyPairCopy;
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
**Deprecation Warning**: It is recommended that [libsignal-protocol-c](https://github.com/whispersystems/libsignal-protocol-c) be used for all new applications.
|
||||
**Deprecation Warning**: It is recommended that the swift interface of [libsignal-client](https://github.com/signalapp/libsignal-client) be used for all new iOS applications. This library is no longer used by us or maintained.
|
||||
|
||||
|
||||
# SignalProtocolKit [](https://travis-ci.org/WhisperSystems/AxolotlKit)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user