Push SUSignature through SUAppcastItem (like 8ad1f57 on 1.x)

This commit is contained in:
Jordan Rose
2020-06-10 12:14:30 +01:00
committed by Kornel
parent 25d394acda
commit 261f5dc797
14 changed files with 93 additions and 50 deletions
+5 -5
View File
@@ -58,7 +58,7 @@ static const NSTimeInterval SUDisplayProgressTimeDelay = 0.7;
@property (nonatomic, copy) NSString *updateDirectoryPath;
@property (nonatomic, copy) NSString *downloadName;
@property (nonatomic, copy) NSString *decryptionPassword;
@property (nonatomic, copy) NSString *dsaSignature;
@property (nonatomic, strong) SUSignatures *signatures;
@property (nonatomic, copy) NSString *relaunchPath;
@property (nonatomic, copy) NSString *installationType;
@property (nonatomic, assign) BOOL shouldRelaunch;
@@ -91,7 +91,7 @@ static const NSTimeInterval SUDisplayProgressTimeDelay = 0.7;
@synthesize updateDirectoryPath = _updateDirectoryPath;
@synthesize downloadName = _downloadName;
@synthesize decryptionPassword = _decryptionPassword;
@synthesize dsaSignature = _dsaSignature;
@synthesize signatures = _signatures;
@synthesize relaunchPath = _relaunchPath;
@synthesize installationType = _installationType;
@synthesize shouldRelaunch = _shouldRelaunch;
@@ -198,7 +198,7 @@ static const NSTimeInterval SUDisplayProgressTimeDelay = 0.7;
// Normal application updates are a bit more lenient allowing developers to change one of apple dev ID or DSA keys
BOOL needsPrevalidation = [[unarchiver class] unsafeIfArchiveIsNotValidated] || ![self.installationType isEqualToString:SPUInstallationTypeApplication];
self.updateValidator = [[SUUpdateValidator alloc] initWithDownloadPath:archivePath dsaSignature:self.dsaSignature host:self.host performingPrevalidation:needsPrevalidation];
self.updateValidator = [[SUUpdateValidator alloc] initWithDownloadPath:archivePath signatures:self.signatures host:self.host performingPrevalidation:needsPrevalidation];
success = self.updateValidator.canValidate;
}
@@ -251,7 +251,7 @@ static const NSTimeInterval SUDisplayProgressTimeDelay = 0.7;
self.updateDirectoryPath = nil;
self.downloadName = nil;
self.decryptionPassword = nil;
self.dsaSignature = nil;
self.signatures = nil;
self.relaunchPath = nil;
self.host = nil;
@@ -387,7 +387,7 @@ static const NSTimeInterval SUDisplayProgressTimeDelay = 0.7;
self.installationType = installationType;
self.relaunchPath = installationData.relaunchPath;
self.downloadName = installationData.downloadName;
self.dsaSignature = installationData.dsaSignature;
self.signatures = installationData.signatures;
self.updateDirectoryPath = cacheInstallationPath;
self.host = [[SUHost alloc] initWithBundle:hostBundle];
+5 -3
View File
@@ -8,6 +8,8 @@
#import <Foundation/Foundation.h>
@class SUSignatures;
NS_ASSUME_NONNULL_BEGIN
@interface SPUInstallationInputData : NSObject <NSSecureCoding>
@@ -17,17 +19,17 @@ NS_ASSUME_NONNULL_BEGIN
* hostBundlePath - path to host bundle to update & replace
* updateDirectoryPath - path to update directory (i.e, temporary directory containing the new update archive)
* downloadName - name of update archive in update directory
* dsaSignature - DSA signature for the update that came from the appcast item
* signatures - signatures for the update that came from the appcast item
* decryptionPassword - optional decryption password for dmg archives
*/
- (instancetype)initWithRelaunchPath:(NSString *)relaunchPath hostBundlePath:(NSString *)hostBundlePath updateDirectoryPath:(NSString *)updateDirectoryPath downloadName:(NSString *)downloadName installationType:(NSString *)installationType dsaSignature:(NSString *)dsaSignature decryptionPassword:(nullable NSString *)decryptionPassword;
- (instancetype)initWithRelaunchPath:(NSString *)relaunchPath hostBundlePath:(NSString *)hostBundlePath updateDirectoryPath:(NSString *)updateDirectoryPath downloadName:(NSString *)downloadName installationType:(NSString *)installationType signatures:(SUSignatures *)signatures decryptionPassword:(nullable NSString *)decryptionPassword;
@property (nonatomic, copy, readonly) NSString *relaunchPath;
@property (nonatomic, copy, readonly) NSString *hostBundlePath;
@property (nonatomic, copy, readonly) NSString *updateDirectoryPath;
@property (nonatomic, copy, readonly) NSString *downloadName;
@property (nonatomic, copy, readonly) NSString *installationType;
@property (nonatomic, copy, readonly) NSString *dsaSignature;
@property (nonatomic, strong, readonly) SUSignatures *signatures;
@property (nonatomic, copy, readonly, nullable) NSString *decryptionPassword;
@end
+9 -9
View File
@@ -8,7 +8,7 @@
#import "SPUInstallationInputData.h"
#import "SPUInstallationType.h"
#import "SUSignatures.h"
#include "AppKitPrevention.h"
@@ -16,7 +16,7 @@ static NSString *SURelaunchPathKey = @"SURelaunchPath";
static NSString *SUHostBundlePathKey = @"SUHostBundlePath";
static NSString *SUUpdateDirectoryPathKey = @"SUUpdateDirectoryPath";
static NSString *SUDownloadNameKey = @"SUDownloadName";
static NSString *SUDSASignatureKey = @"SUDSASignature";
static NSString *SUSignaturesKey = @"SUSignatures";
static NSString *SUDecryptionPasswordKey = @"SUDecryptionPassword";
static NSString *SUInstallationTypeKey = @"SUInstallationType";
@@ -26,11 +26,11 @@ static NSString *SUInstallationTypeKey = @"SUInstallationType";
@synthesize hostBundlePath = _hostBundlePath;
@synthesize updateDirectoryPath = _updateDirectoryPath;
@synthesize downloadName = _downloadName;
@synthesize dsaSignature = _dsaSignature;
@synthesize signatures = _signatures;
@synthesize decryptionPassword = _decryptionPassword;
@synthesize installationType = _installationType;
- (instancetype)initWithRelaunchPath:(NSString *)relaunchPath hostBundlePath:(NSString *)hostBundlePath updateDirectoryPath:(NSString *)updateDirectoryPath downloadName:(NSString *)downloadName installationType:(NSString *)installationType dsaSignature:(NSString *)dsaSignature decryptionPassword:(nullable NSString *)decryptionPassword
- (instancetype)initWithRelaunchPath:(NSString *)relaunchPath hostBundlePath:(NSString *)hostBundlePath updateDirectoryPath:(NSString *)updateDirectoryPath downloadName:(NSString *)downloadName installationType:(NSString *)installationType signatures:(SUSignatures *)signatures decryptionPassword:(nullable NSString *)decryptionPassword
{
self = [super init];
if (self != nil) {
@@ -42,7 +42,7 @@ static NSString *SUInstallationTypeKey = @"SUInstallationType";
_installationType = [installationType copy];
assert(SPUValidInstallationType(_installationType));
_dsaSignature = [dsaSignature copy];
_signatures = signatures;
_decryptionPassword = [decryptionPassword copy];
}
return self;
@@ -75,14 +75,14 @@ static NSString *SUInstallationTypeKey = @"SUInstallationType";
return nil;
}
NSString *dsaSignature = [decoder decodeObjectOfClass:[NSString class] forKey:SUDSASignatureKey];
if (dsaSignature == nil) {
SUSignatures *signatures = [decoder decodeObjectOfClass:[SUSignatures class] forKey:SUSignaturesKey];
if (signatures == nil) {
return nil;
}
NSString *decryptionPassword = [decoder decodeObjectOfClass:[NSString class] forKey:SUDecryptionPasswordKey];
return [self initWithRelaunchPath:relaunchPath hostBundlePath:hostBundlePath updateDirectoryPath:updateDirectoryPath downloadName:downloadName installationType:installationType dsaSignature:dsaSignature decryptionPassword:decryptionPassword];
return [self initWithRelaunchPath:relaunchPath hostBundlePath:hostBundlePath updateDirectoryPath:updateDirectoryPath downloadName:downloadName installationType:installationType signatures:signatures decryptionPassword:decryptionPassword];
}
- (void)encodeWithCoder:(NSCoder *)coder
@@ -92,7 +92,7 @@ static NSString *SUInstallationTypeKey = @"SUInstallationType";
[coder encodeObject:self.updateDirectoryPath forKey:SUUpdateDirectoryPathKey];
[coder encodeObject:self.installationType forKey:SUInstallationTypeKey];
[coder encodeObject:self.downloadName forKey:SUDownloadNameKey];
[coder encodeObject:self.dsaSignature forKey:SUDSASignatureKey];
[coder encodeObject:self.signatures forKey:SUSignaturesKey];
if (self.decryptionPassword != nil) {
[coder encodeObject:self.decryptionPassword forKey:SUDecryptionPasswordKey];
}
+1 -1
View File
@@ -25,7 +25,7 @@
@interface SUDSAVerifier : NSObject
+ (BOOL)validatePath:(NSString *)path withEncodedDSASignature:(NSString *)encodedSignature withPublicDSAKey:(NSString *)pkeyString;
+ (BOOL)validatePath:(NSString *)path withDSASignature:(NSData *)signature withPublicDSAKey:(NSString *)pkeyString;
- (instancetype)initWithPublicKeyData:(NSData *)data;
+2 -9
View File
@@ -23,9 +23,9 @@
SecKeyRef _secKey;
}
+ (BOOL)validatePath:(NSString *)path withEncodedDSASignature:(NSString *)encodedSignature withPublicDSAKey:(NSString *)pkeyString
+ (BOOL)validatePath:(NSString *)path withDSASignature:(NSData *)signature withPublicDSAKey:(NSString *)pkeyString
{
if (!encodedSignature) {
if (!signature) {
SULog(SULogLevelError, @"There is no DSA signature to check");
return NO;
}
@@ -40,13 +40,6 @@
return NO;
}
NSString *strippedSignature = [encodedSignature stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet];
NSData *signature =
#if __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_9
[[NSData alloc] initWithBase64Encoding:strippedSignature];
#else
[[NSData alloc] initWithBase64EncodedString:strippedSignature options:NSDataBase64DecodingIgnoreUnknownCharacters];
#endif
return [verifier verifyFileAtPath:path signature:signature];
}
+2
View File
@@ -51,6 +51,7 @@
55C14F07136EF6DB00649790 /* SULog.m in Sources */ = {isa = PBXBuildFile; fileRef = 55C14F05136EF6DB00649790 /* SULog.m */; };
55E6F33319EC9F6C00005E76 /* SUErrors.h in Headers */ = {isa = PBXBuildFile; fileRef = 55E6F33219EC9F6C00005E76 /* SUErrors.h */; settings = {ATTRIBUTES = (Public, ); }; };
5A4094481C74EA5200983BE0 /* SUAppcastTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AA4DCD01C73E5510078F128 /* SUAppcastTest.swift */; };
5A6DD17123FE1FFC000AEF33 /* SUSignatures.m in Sources */ = {isa = PBXBuildFile; fileRef = EA1E286D22B665E8004AA304 /* SUSignatures.m */; };
5AD0FA7F1C73F2E2004BCEFF /* testappcast.xml in Resources */ = {isa = PBXBuildFile; fileRef = 5AD0FA7E1C73F2E2004BCEFF /* testappcast.xml */; };
5AE459001C34118500E3BB47 /* SUUpdaterTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 14950074195FDF5900BC5B5B /* SUUpdaterTest.m */; };
5AE459021C34118500E3BB47 /* SUVersionComparisonTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 61227A150DB548B800AB99EA /* SUVersionComparisonTest.m */; };
@@ -3494,6 +3495,7 @@
7267E5C21D3D8B2700D1BF90 /* SUGuidedPackageInstaller.m in Sources */,
7267E5D71D3D8D3F00D1BF90 /* SUHost.m in Sources */,
7267E5C31D3D8B2700D1BF90 /* SUInstaller.m in Sources */,
5A6DD17123FE1FFC000AEF33 /* SUSignatures.m in Sources */,
7267E5CE1D3D8C7500D1BF90 /* SULog.m in Sources */,
7267E5C41D3D8B2700D1BF90 /* SUPackageInstaller.m in Sources */,
7267E5871D3D89B300D1BF90 /* SUPipedUnarchiver.m in Sources */,
+2 -4
View File
@@ -171,15 +171,13 @@
pathToRelaunch = relaunchPath;
}
}
NSString *dsaSignature = (self.updateItem.DSASignature == nil) ? @"" : self.updateItem.DSASignature;
NSString *decryptionPassword = nil;
if ([self.updaterDelegate respondsToSelector:@selector(decryptionPasswordForUpdater:)]) {
decryptionPassword = [self.updaterDelegate decryptionPasswordForUpdater:self.updater];
}
SPUInstallationInputData *installationData = [[SPUInstallationInputData alloc] initWithRelaunchPath:pathToRelaunch hostBundlePath:self.host.bundlePath updateDirectoryPath:self.temporaryDirectory downloadName:self.downloadName installationType:self.updateItem.installationType dsaSignature:dsaSignature decryptionPassword:decryptionPassword];
SPUInstallationInputData *installationData = [[SPUInstallationInputData alloc] initWithRelaunchPath:pathToRelaunch hostBundlePath:self.host.bundlePath updateDirectoryPath:self.temporaryDirectory downloadName:self.downloadName installationType:self.updateItem.installationType signatures:self.updateItem.signatures decryptionPassword:decryptionPassword];
NSData *archivedData = SPUArchiveRootObjectSecurely(installationData);
if (archivedData == nil) {
+2 -1
View File
@@ -11,13 +11,14 @@
#import <Foundation/Foundation.h>
#import <Sparkle/SUExport.h>
@class SUSignatures;
SU_EXPORT @interface SUAppcastItem : NSObject<NSSecureCoding>
@property (copy, readonly) NSString *title;
@property (copy, readonly) NSString *dateString;
@property (copy, readonly) NSString *itemDescription;
@property (strong, readonly) NSURL *releaseNotesURL;
@property (copy, readonly) NSString *DSASignature;
@property (strong, readonly) SUSignatures *signatures;
@property (copy, readonly) NSString *minimumSystemVersion;
@property (copy, readonly) NSString *maximumSystemVersion;
@property (strong, readonly) NSURL *fileURL;
+7 -6
View File
@@ -10,6 +10,7 @@
#import <Sparkle/SUVersionComparisonProtocol.h>
#import "SULog.h"
#import "SUConstants.h"
#import "SUSignatures.h"
#import "SPUInstallationType.h"
@@ -17,7 +18,7 @@
static NSString *SUAppcastItemDeltaUpdatesKey = @"deltaUpdates";
static NSString *SUAppcastItemDisplayVersionStringKey = @"displayVersionString";
static NSString *SUAppcastItemDSASignatureKey = @"DSASignature";
static NSString *SUAppcastItemSignaturesKey = @"signatures";
static NSString *SUAppcastItemFileURLKey = @"fileURL";
static NSString *SUAppcastItemInfoURLKey = @"infoURL";
static NSString *SUAppcastItemContentLengthKey = @"contentLength";
@@ -35,7 +36,7 @@ static NSString *SUAppcastItemInstallationTypeKey = @"SUAppcastItemInstallationT
@synthesize dateString = _dateString;
@synthesize deltaUpdates = _deltaUpdates;
@synthesize displayVersionString = _displayVersionString;
@synthesize DSASignature = _DSASignature;
@synthesize signatures = _signatures;
@synthesize fileURL = _fileURL;
@synthesize contentLength = _contentLength;
@synthesize infoURL = _infoURL;
@@ -61,7 +62,7 @@ static NSString *SUAppcastItemInstallationTypeKey = @"SUAppcastItemInstallationT
if (self != nil) {
_deltaUpdates = [decoder decodeObjectOfClasses:[NSSet setWithArray:@[[NSDictionary class], [SUAppcastItem class]]] forKey:SUAppcastItemDeltaUpdatesKey];
_displayVersionString = [(NSString *)[decoder decodeObjectOfClass:[NSString class] forKey:SUAppcastItemDisplayVersionStringKey] copy];
_DSASignature = [(NSString *)[decoder decodeObjectOfClass:[NSString class] forKey:SUAppcastItemDSASignatureKey] copy];
_signatures = (SUSignatures *)[decoder decodeObjectOfClass:[SUSignatures class] forKey:SUAppcastItemSignaturesKey];
_fileURL = [decoder decodeObjectOfClass:[NSURL class] forKey:SUAppcastItemFileURLKey];
_infoURL = [decoder decodeObjectOfClass:[NSURL class] forKey:SUAppcastItemInfoURLKey];
@@ -94,8 +95,8 @@ static NSString *SUAppcastItemInstallationTypeKey = @"SUAppcastItemInstallationT
[encoder encodeObject:self.displayVersionString forKey:SUAppcastItemDisplayVersionStringKey];
}
if (self.DSASignature != nil) {
[encoder encodeObject:self.DSASignature forKey:SUAppcastItemDSASignatureKey];
if (self.signatures != nil) {
[encoder encodeObject:self.signatures forKey:SUAppcastItemSignaturesKey];
}
if (self.fileURL != nil) {
@@ -250,7 +251,7 @@ static NSString *SUAppcastItemInstallationTypeKey = @"SUAppcastItemInstallationT
_fileURL = [NSURL URLWithString:fileURLString];
}
if (enclosure) {
_DSASignature = [(NSString *)[enclosure objectForKey:SUAppcastAttributeDSASignature] copy];
_signatures = [[SUSignatures alloc] initWithDsa:[enclosure objectForKey:SUAppcastAttributeDSASignature] ed:nil];
}
_versionString = [(NSString *)newVersion copy];
+1 -1
View File
@@ -16,7 +16,7 @@
NS_ASSUME_NONNULL_BEGIN
@interface SUSignatures : NSObject {
@interface SUSignatures : NSObject <NSSecureCoding> {
unsigned char ed25519_signature[64];
}
@property (strong, readonly, nullable) NSData *dsaSignature;
+42
View File
@@ -10,6 +10,9 @@
#import <assert.h>
#import "SULog.h"
static NSString *SUDSASignatureKey = @"SUDSASignature";
static NSString *SUEDSignatureKey = @"SUEDSignature";
@implementation SUSignatures
@synthesize dsaSignature = _dsaSignature;
@@ -51,6 +54,45 @@ static NSData *decode(NSString *str) {
#pragma clang diagnostic pop
}
- (instancetype)initWithCoder:(NSCoder *)decoder
{
self = [super init];
if (self) {
NSData *dsaSignature = [decoder decodeObjectOfClass:[NSData class] forKey:SUDSASignatureKey];
if (dsaSignature) {
_dsaSignature = dsaSignature;
}
NSData *edSignature = [decoder decodeObjectOfClass:[NSData class] forKey:SUEDSignatureKey];
if (edSignature) {
if (edSignature.length != sizeof(self->ed25519_signature)) {
return nil;
}
[edSignature getBytes:self->ed25519_signature];
}
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)coder
{
if (self.dsaSignature) {
[coder encodeObject:self.dsaSignature forKey:SUDSASignatureKey];
}
if (self.ed25519Signature) {
// Xcode may enable this in pedantic mode
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdirect-ivar-access"
NSData *edSignature = [NSData dataWithBytesNoCopy:&self->ed25519_signature length:sizeof(self->ed25519_signature) freeWhenDone:false];
#pragma clang diagnostic pop
[coder encodeObject:edSignature forKey:SUEDSignatureKey];
}
}
+ (BOOL)supportsSecureCoding {
return YES;
}
@end
@implementation SUPublicKeys
+2 -1
View File
@@ -9,11 +9,12 @@
#import <Foundation/Foundation.h>
@class SUHost;
@class SUSignatures;
@interface SUUpdateValidator : NSObject
// Pass YES to performingPrevalidation if archive validation must be done immediately, before extraction
- (instancetype)initWithDownloadPath:(NSString *)downloadPath dsaSignature:(NSString *)dsaSignature host:(SUHost *)host performingPrevalidation:(BOOL)performingPrevalidation;
- (instancetype)initWithDownloadPath:(NSString *)downloadPath signatures:(SUSignatures *)signatures host:(SUHost *)host performingPrevalidation:(BOOL)performingPrevalidation;
// Indicates whether we can perform (post) validation later
@property (nonatomic, readonly) BOOL canValidate;
+11 -9
View File
@@ -12,6 +12,7 @@
#import "SUInstaller.h"
#import "SUHost.h"
#import "SULog.h"
#import "SUSignatures.h"
#include "AppKitPrevention.h"
@@ -20,7 +21,7 @@
@property (nonatomic, readonly) SUHost *host;
@property (nonatomic, readonly) BOOL prevalidatedDsaSignature;
@property (nonatomic, readonly) NSString *dsaSignature;
@property (nonatomic, readonly) SUSignatures *signatures;
@property (nonatomic, readonly) NSString *downloadPath;
@end
@@ -30,10 +31,10 @@
@synthesize host = _host;
@synthesize canValidate = _canValidate;
@synthesize prevalidatedDsaSignature = _prevalidatedDsaSignature;
@synthesize dsaSignature = _dsaSignature;
@synthesize signatures = _signatures;
@synthesize downloadPath = _downloadPath;
- (instancetype)initWithDownloadPath:(NSString *)downloadPath dsaSignature:(NSString *)dsaSignature host:(SUHost *)host performingPrevalidation:(BOOL)performingPrevalidation
- (instancetype)initWithDownloadPath:(NSString *)downloadPath signatures:(SUSignatures *)signatures host:(SUHost *)host performingPrevalidation:(BOOL)performingPrevalidation
{
self = [super init];
if (self != nil) {
@@ -41,6 +42,7 @@
BOOL prevalidatedDsaSignature;
if (performingPrevalidation) {
NSString *publicDSAKey = host.publicDSAKey;
NSData *dsaSignature = signatures.dsaSignature;
if (publicDSAKey == nil) {
prevalidatedDsaSignature = NO;
@@ -49,7 +51,7 @@
prevalidatedDsaSignature = NO;
SULog(SULogLevelError, @"Failed to validate update before unarchiving because no DSA signature was found");
} else {
prevalidatedDsaSignature = [SUDSAVerifier validatePath:downloadPath withEncodedDSASignature:dsaSignature withPublicDSAKey:host.publicDSAKey];
prevalidatedDsaSignature = [SUDSAVerifier validatePath:downloadPath withDSASignature:dsaSignature withPublicDSAKey:host.publicDSAKey];
if (!prevalidatedDsaSignature) {
SULog(SULogLevelError, @"DSA signature validation before unarchiving failed for update %@", downloadPath);
}
@@ -64,7 +66,7 @@
_canValidate = canValidate;
_prevalidatedDsaSignature = prevalidatedDsaSignature;
_downloadPath = [downloadPath copy];
_dsaSignature = [dsaSignature copy];
_signatures = signatures;
_host = host;
}
return self;
@@ -74,7 +76,7 @@
{
assert(self.canValidate);
NSString *DSASignature = self.dsaSignature;
NSData *DSASignature = self.signatures.dsaSignature;
NSString *downloadPath = self.downloadPath;
SUHost *host = self.host;
@@ -96,7 +98,7 @@
if (isPackage) {
// If we get here, then the appcast installation type was lying to us.. This error will be caught later when starting the installer.
// For package type updates, all we do is check if the DSA signature is valid
BOOL validationCheckSuccess = [SUDSAVerifier validatePath:downloadPath withEncodedDSASignature:DSASignature withPublicDSAKey:host.publicDSAKey];
BOOL validationCheckSuccess = [SUDSAVerifier validatePath:downloadPath withDSASignature:DSASignature withPublicDSAKey:host.publicDSAKey];
if (!validationCheckSuccess) {
SULog(SULogLevelError, @"DSA signature validation of the package failed. The update contains an installer package, and valid DSA signatures are mandatory for all installer packages. The update will be rejected. Sign the installer with a valid DSA key or use an .app bundle update instead.");
}
@@ -121,7 +123,7 @@
}
}
- (BOOL)validateBundleUpdateForHost:(SUHost *)host newBundleURL:(NSURL *)newBundleURL archivePath:(NSString *)archivePath DSASignature:(NSString *)DSASignature
- (BOOL)validateBundleUpdateForHost:(SUHost *)host newBundleURL:(NSURL *)newBundleURL archivePath:(NSString *)archivePath DSASignature:(NSData *)DSASignature
{
NSBundle *newBundle = [NSBundle bundleWithURL:newBundleURL];
if (newBundle == nil) {
@@ -146,7 +148,7 @@
// In that case, the check ensures that the app author has correctly used DSA keys, so that the app will be updateable in the next version.
// However if the new and old DSA keys are the same, then this is a security measure.
if (newPublicDSAKey != nil) {
if (![SUDSAVerifier validatePath:archivePath withEncodedDSASignature:DSASignature withPublicDSAKey:newPublicDSAKey]) {
if (![SUDSAVerifier validatePath:archivePath withDSASignature:DSASignature withPublicDSAKey:newPublicDSAKey]) {
SULog(SULogLevelError, @"DSA signature validation failed. The update has a public DSA key and is signed with a DSA key, but the %@ doesn't match the signature. The update will be rejected.",
dsaKeysMatch ? @"public key" : @"new public key shipped with the update");
return NO;
+2 -1
View File
@@ -75,9 +75,10 @@
- (void)testValidatePath
{
NSString *pubkey = [NSString stringWithContentsOfFile:self.pubKeyFile encoding:NSASCIIStringEncoding error:nil];
NSData *signature = [[NSData alloc] initWithBase64EncodedString:@"MC0CFFMF3ha5kjvrJ9JTpTR8BenPN9QUAhUAzY06JRdtP17MJewxhK0twhvbKIE=" options:(NSDataBase64DecodingOptions)0];
XCTAssertTrue([SUDSAVerifier validatePath:self.testFile
withEncodedDSASignature:@"MC0CFFMF3ha5kjvrJ9JTpTR8BenPN9QUAhUAzY06JRdtP17MJewxhK0twhvbKIE="
withDSASignature:signature
withPublicDSAKey:pubkey],
@"Expected valid signature");
}