Signal-iOS/SignalServiceKit/Messages/PreKeyBundle+jsonDict.m
2024-03-27 12:27:06 -05:00

133 lines
5.1 KiB
Objective-C

//
// Copyright 2017 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
#import "PreKeyBundle+jsonDict.h"
#import <SignalCoreKit/NSData+OWS.h>
NS_ASSUME_NONNULL_BEGIN
@implementation PreKeyBundle (jsonDict)
+ (nullable PreKeyBundle *)preKeyBundleFromDictionary:(NSDictionary *)dictionary forDeviceNumber:(NSNumber *)number
{
PreKeyBundle *bundle = nil;
id identityKeyObject = [dictionary objectForKey:@"identityKey"];
if (![identityKeyObject isKindOfClass:[NSString class]]) {
OWSFailDebug(@"Unexpected identityKeyObject: %@", [identityKeyObject class]);
return nil;
}
NSString *identityKeyString = (NSString *)identityKeyObject;
id devicesObject = [dictionary objectForKey:@"devices"];
if (![devicesObject isKindOfClass:[NSArray class]]) {
OWSFailDebug(@"Unexpected devicesObject: %@", [devicesObject class]);
return nil;
}
NSArray *devicesArray = (NSArray *)devicesObject;
NSData *identityKey = [NSData dataFromBase64StringNoPadding:identityKeyString];
for (NSDictionary *deviceDict in devicesArray) {
NSNumber *registrationIdString = [deviceDict objectForKey:@"registrationId"];
NSNumber *deviceIdString = [deviceDict objectForKey:@"deviceId"];
if (!(registrationIdString && deviceIdString)) {
OWSLogError(@"Failed to get the registration id and device id");
return nil;
}
if (![deviceIdString isEqualToNumber:number]) {
OWSLogWarn(@"Got a keyid for another device");
return nil;
}
int registrationId = [registrationIdString intValue];
int deviceId = [deviceIdString intValue];
NSDictionary *_Nullable preKeyDict;
id optionalPreKeyDict = [deviceDict objectForKey:@"preKey"];
// JSON parsing might give us NSNull, so we can't simply check for non-nil.
if ([optionalPreKeyDict isKindOfClass:[NSDictionary class]]) {
preKeyDict = (NSDictionary *)optionalPreKeyDict;
}
int prekeyId;
NSData *_Nullable preKeyPublic;
if (!preKeyDict) {
OWSLogInfo(@"No one-time prekey included in the bundle.");
prekeyId = -1;
} else {
prekeyId = [[preKeyDict objectForKey:@"keyId"] intValue];
NSString *preKeyPublicString = [preKeyDict objectForKey:@"publicKey"];
preKeyPublic = [NSData dataFromBase64StringNoPadding:preKeyPublicString];
}
NSDictionary *signedPrekey = [deviceDict objectForKey:@"signedPreKey"];
if (![signedPrekey isKindOfClass:[NSDictionary class]]) {
OWSLogError(@"Device doesn't have signed prekeys registered");
return nil;
}
NSNumber *signedKeyIdNumber = [signedPrekey objectForKey:@"keyId"];
NSString *signedSignatureString = [signedPrekey objectForKey:@"signature"];
NSString *signedPublicKeyString = [signedPrekey objectForKey:@"publicKey"];
int pqPreKeyId;
NSData *_Nullable pqPreKeyPublic;
NSData *_Nullable pqPreKeySignature;
NSDictionary *pqPreKeyDict = [deviceDict objectForKey:@"pqPreKey"];
if (![pqPreKeyDict isKindOfClass:[NSDictionary class]]) {
OWSLogInfo(@"No one-time pq prekey included in the bundle.");
pqPreKeyId = -1;
} else {
pqPreKeyId = [[pqPreKeyDict objectForKey:@"keyId"] intValue];
NSString *pqPreKeyPublicString = [pqPreKeyDict objectForKey:@"publicKey"];
pqPreKeyPublic = [NSData dataFromBase64StringNoPadding:pqPreKeyPublicString];
NSString *pqPreKeySignatureString = [pqPreKeyDict objectForKey:@"signature"];
pqPreKeySignature = [NSData dataFromBase64StringNoPadding:pqPreKeySignatureString];
}
if (!(signedKeyIdNumber && signedPublicKeyString && signedSignatureString)) {
OWSLogError(@"Missing signed key material");
return nil;
}
NSData *signedPrekeyPublic = [NSData dataFromBase64StringNoPadding:signedPublicKeyString];
NSData *signedPreKeySignature = [NSData dataFromBase64StringNoPadding:signedSignatureString];
if (!(signedPrekeyPublic && signedPreKeySignature)) {
OWSLogError(@"Failed to parse signed keying material");
return nil;
}
int signedPreKeyId = [signedKeyIdNumber intValue];
bundle = [[self alloc] initWithRegistrationId:registrationId
deviceId:deviceId
preKeyId:prekeyId
preKeyPublic:preKeyPublic
signedPreKeyPublic:signedPrekeyPublic
signedPreKeyId:signedPreKeyId
signedPreKeySignature:signedPreKeySignature
pqPreKeyId:pqPreKeyId
pqPreKeyPublic:pqPreKeyPublic
pqPreKeySignature:pqPreKeySignature
identityKey:identityKey];
}
return bundle;
}
@end
NS_ASSUME_NONNULL_END