Compare commits

...

34 Commits

Author SHA1 Message Date
Nora Trapp
06c654a757
Update README.md 2021-04-08 10:21:14 -07:00
Nora Trapp
36601e4bbe Don't archive sessions when they are fresh. 2021-01-16 18:04:32 -08:00
Nora Trapp
9413e47751 Increase ratchet counter limit 2021-01-16 12:49:24 -08:00
Nora Trapp
c40a9fb072 Fix tests 2020-11-12 17:45:51 -08:00
Nora Trapp
18a7031342 Merge branch 'nt/fix-missing-session-issues' 2020-11-12 17:27:02 -08:00
Nora Trapp
43aa55e6be PR Feedback 2020-11-12 17:26:50 -08:00
Nora Trapp
89c447b636 Add additional logging for decryption errors 2020-11-12 17:24:46 -08:00
Nora Trapp
170acafbc8 Only check identity key changes if our current session state has an identity key 2020-11-12 17:24:46 -08:00
Nora Trapp
99d700a87c Don't purge previous session states after identity key change or promote previous session states after decryption. 2020-11-12 17:23:49 -08:00
Matthew Chen
582ec1a96c Merge branch 'charlesmchen/sessionLogging' 2020-11-12 17:20:55 -03:00
Matthew Chen
8f8d565412 Improve logging around sessions. 2020-11-11 10:19:51 -03:00
Matthew Chen
0516a98a55 Merge branch 'charlesmchen/missingEphemeralPrekey' 2020-10-23 18:45:10 -03:00
Matthew Chen
f0632b87bb Improve logging around missing ephemeral prekeys. 2020-10-23 16:09:52 -03:00
Matthew Chen
97ae15634e Merge branch 'charlesmchen/prekeyLifecycle' 2020-08-25 21:24:50 -03:00
Matthew Chen
34073098e9 Use protocol contexts in prekey stores. 2020-08-25 20:27:11 -03:00
Matthew Chen
61ce278894 Use protocol contexts in prekey stores. 2020-08-25 20:19:43 -03:00
Matthew Chen
852d43fe8d Use protocol contexts in prekey stores. 2020-08-25 20:08:38 -03:00
Michael Kirk
debc5cb311 Merge branch 'mkirk/compiler-warnings' 2020-03-09 16:49:17 -06:00
Michael Kirk
6a1c548be0 fix compiler warnings: missing nullability annotations 2019-12-16 17:47:16 -08:00
Matthew Chen
97bc4ea101 Merge branch 'charlesmchen/fixBrokenTests' 2019-11-07 17:19:02 -03:00
Matthew Chen
ddcdbd04da Fix broken tests. 2019-11-07 13:27:48 -03:00
Matthew Chen
905c5d0e0c Merge branch 'charlesmchen/prekeyManagement' 2019-11-02 08:14:31 -03:00
Matthew Chen
fb8ca529ae Delete old and unused one-time prekeys.
Thanks Mikunj Varsani for the bug report.
2019-11-01 12:54:06 -03:00
Nora Trapp
4a4899ea14 Merge branch 'nt/deployment-target' 2019-09-23 16:52:14 -07:00
Nora Trapp
1c5425eb26 Update deployment target to iOS 10 2019-09-23 10:46:21 -07:00
Michael Kirk
8d4451262d Merge branch 'mkirk/missing-nullability-macros' 2019-06-19 10:08:44 -06:00
Michael Kirk
832cb97c95 add missing nullability macros 2019-06-19 10:08:32 -06:00
Michael Kirk
9bdcbaade2 Merge branch 'mkirk/typed-protocol-context' 2019-05-22 14:57:45 -04:00
Michael Kirk
d1739b2669 Apply ReadContext 2019-05-22 12:00:19 -04:00
Michael Kirk
3fe60a30fe rename ProtocolContext -> SPKProtocolWriteContext 2019-05-22 10:50:45 -04:00
Matthew Chen
41c6a84b46 Add ProtocolContext Protocol. 2019-05-22 10:40:09 -04:00
Michael Kirk
aa4b0a7bfa Merge branch 'mkirk/no-throws-on-load' 2019-05-21 11:08:55 -04:00
Michael Kirk
f852496e31 Move throw from loadPreKey protocol to AxolotlKit 2019-05-13 15:42:21 -06:00
Michael Kirk
dedb0f987a Merge branch 'mkirk/fixup-tests' 2018-11-12 09:21:02 -06:00
28 changed files with 290 additions and 194 deletions

View File

@ -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

View File

@ -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";

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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];

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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];
}
}

View File

@ -39,6 +39,8 @@
@property(nonatomic)int remoteRegistrationId;
@property(nonatomic)int localRegistrationId;
@property (nonatomic, readonly) BOOL isFresh;
- (NSData*)senderRatchetKey;
- (ECKeyPair*)senderRatchetKeyPair;

View File

@ -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];
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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];
}

View File

@ -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

View File

@ -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

View 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

View File

@ -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

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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 [![Build Status](https://travis-ci.org/WhisperSystems/AxolotlKit.svg?branch=master)](https://travis-ci.org/WhisperSystems/AxolotlKit)