Skip to content

Commit

Permalink
Switch test to NSURL
Browse files Browse the repository at this point in the history
  • Loading branch information
kornelski committed Sep 2, 2016
1 parent 64af6d0 commit c7a7704
Showing 1 changed file with 74 additions and 76 deletions.
150 changes: 74 additions & 76 deletions Tests/SUCodeSigningVerifierTest.m
Expand Up @@ -15,54 +15,48 @@

@interface SUCodeSigningVerifierTest : XCTestCase

@property (copy) NSString *notSignedAppPath;
@property (copy) NSString *notSignedAppURL;
@property (copy) NSString *validSignedAppPath;
@property (copy) NSString *invalidSignedAppPath;
@property (copy) NSString *calculatorCopyPath;
@property (copy) NSURL *notSignedAppURL;
@property (copy) NSURL *validSignedAppURL;
@property (copy) NSURL *invalidSignedAppURL;
@property (copy) NSURL *calculatorCopyURL;

@end

@implementation SUCodeSigningVerifierTest

@synthesize notSignedAppPath = _notSignedAppPath;
@synthesize notSignedAppURL = _notSignedAppURL;
@synthesize validSignedAppPath = _validSignedAppPath;
@synthesize invalidSignedAppPath = _invalidSignedAppPath;
@synthesize calculatorCopyPath = _calculatorCopyPath;
@synthesize validSignedAppURL = _validSignedAppURL;
@synthesize invalidSignedAppURL = _invalidSignedAppURL;
@synthesize calculatorCopyURL = _calculatorCopyURL;

- (void)setUp
{
[super setUp];

NSBundle *unitTestBundle = [NSBundle bundleForClass:[self class]];
NSString *unitTestBundleIdentifier = unitTestBundle.bundleIdentifier;
NSString *zippedAppPath = [unitTestBundle pathForResource:@"SparkleTestCodeSignApp" ofType:@"zip"];
NSString *zippedAppURL = [unitTestBundle pathForResource:@"SparkleTestCodeSignApp" ofType:@"zip"];

SUFileManager *fileManager = [SUFileManager defaultManager];

NSError *tempError = nil;
NSURL *tempDir = [fileManager makeTemporaryDirectoryWithPreferredName:unitTestBundleIdentifier appropriateForDirectoryURL:[NSURL fileURLWithPath:zippedAppPath] error:&tempError];
NSURL *tempDir = [fileManager makeTemporaryDirectoryWithPreferredName:unitTestBundleIdentifier appropriateForDirectoryURL:[NSURL fileURLWithPath:zippedAppURL] error:&tempError];

if (tempDir == nil) {
XCTFail(@"Failed to create temporary directory with error: %@", tempError);
return;
}

NSString *tempDirPath = tempDir.path;
XCTAssertNotNil(tempDirPath);


NSError *error = nil;
if ([[NSFileManager defaultManager] createDirectoryAtPath:tempDirPath withIntermediateDirectories:YES attributes:nil error:&error]) {
if ([self unzip:zippedAppPath toPath:tempDirPath]) {
self.notSignedAppPath = [tempDirPath stringByAppendingPathComponent:@"SparkleTestCodeSignApp.app"];
self.notSignedAppURL = [NSURL fileURLWithPath:self.notSignedAppPath];
if ([[NSFileManager defaultManager] createDirectoryAtURL:tempDir withIntermediateDirectories:YES attributes:nil error:&error]) {
if ([self unzip:zippedAppURL toPath:tempDir.path]) {
self.notSignedAppURL = [tempDir URLByAppendingPathComponent:@"SparkleTestCodeSignApp.app"];
[self setupValidSignedApp];
[self setupCalculatorCopy];
[self setupInvalidSignedApp];
}
else {
NSLog(@"Failed to unzip %@", zippedAppPath);
NSLog(@"Failed to unzip %@", zippedAppURL);
}
}
else {
Expand All @@ -73,87 +67,88 @@ - (void)setUp
- (void)tearDown
{
[super tearDown];
if (self.notSignedAppPath) {
NSString *tempDir = [self.notSignedAppPath stringByDeletingLastPathComponent];
[[NSFileManager defaultManager] removeItemAtPath:tempDir error:nil];

if (self.notSignedAppURL) {
NSURL *tempDir = [self.notSignedAppURL URLByDeletingLastPathComponent];
[[NSFileManager defaultManager] removeItemAtURL:tempDir error:nil];
}
}

- (void)setupValidSignedApp
{
NSError *error = nil;
NSString *tempDir = [self.notSignedAppPath stringByDeletingLastPathComponent];
NSString *signedAndValid = [tempDir stringByAppendingPathComponent:@"valid-signed.app"];
if ([[NSFileManager defaultManager] fileExistsAtPath:signedAndValid]) {
[[NSFileManager defaultManager] removeItemAtPath:signedAndValid error:NULL];
NSString *tempDir = [self.notSignedAppURL URLByDeletingLastPathComponent];
NSString *signedAndValid = [tempDir URLByAppendingPathComponent:@"valid-signed.app"];

if ([[NSFileManager defaultManager] fileExistsAtURL:signedAndValid]) {
[[NSFileManager defaultManager] removeItemAtURL:signedAndValid error:NULL];
}
if (![[NSFileManager defaultManager] copyItemAtPath:self.notSignedAppPath toPath:signedAndValid error:&error]) {
XCTFail("Failed to copy %@ to %@ with error: %@", self.notSignedAppPath, signedAndValid, error);

if (![[NSFileManager defaultManager] copyItemAtURL:self.notSignedAppURL toPath:signedAndValid error:&error]) {
XCTFail("Failed to copy %@ to %@ with error: %@", self.notSignedAppURL, signedAndValid, error);
}

self.validSignedAppPath = signedAndValid;

if (![self codesignAppPath:self.validSignedAppPath]) {
XCTFail(@"Failed to codesign %@", self.validSignedAppPath);

self.validSignedAppURL = signedAndValid;
self.validSignedAppURL = [NSURL fileURLWithPath:signedAndValid];

if (![self codesignAppURL:self.validSignedAppURL]) {
XCTFail(@"Failed to codesign %@", self.validSignedAppURL);
}
}

- (void)setupCalculatorCopy
{
NSString *tempDir = [self.notSignedAppPath stringByDeletingLastPathComponent];
NSString *calculatorCopy = [tempDir stringByAppendingPathComponent:@"calc.app"];
if ([[NSFileManager defaultManager] fileExistsAtPath:calculatorCopy]) {
[[NSFileManager defaultManager] removeItemAtPath:calculatorCopy error:NULL];
NSString *tempDir = [self.notSignedAppURL URLByDeletingLastPathComponent];
NSString *calculatorCopy = [tempDir URLByAppendingPathComponent:@"calc.app"];

if ([[NSFileManager defaultManager] fileExistsAtURL:calculatorCopy]) {
[[NSFileManager defaultManager] removeItemAtURL:calculatorCopy error:NULL];
}

// Make a copy of the signed calculator app so we can match signatures later
// Matching signatures on ad-hoc signed apps does *not* work
NSError *copyError = nil;
// Don't check the return value of this operation - seems like on 10.11 the API can say it fails even though the operation really succeeds,
// which sounds like some kind of (SIP / attribute?) bug
[[NSFileManager defaultManager] copyItemAtPath:CALCULATOR_PATH toPath:calculatorCopy error:&copyError];
if (![[NSFileManager defaultManager] fileExistsAtPath:calculatorCopy]) {
[[NSFileManager defaultManager] copyItemAtURL:CALCULATOR_PATH toPath:calculatorCopy error:&copyError];

if (![[NSFileManager defaultManager] fileExistsAtURL:calculatorCopy]) {
XCTFail(@"Copied calculator application does not exist");
}

// Alter the signed copy slightly, this won't invalidate signature matching (although it will invalidate the integrity part of the signature)
// Which is what we want. If a user alters an app bundle, we should still be able to update as long as its identity is still valid
NSError *removeError = nil;
if (![[NSFileManager defaultManager] removeItemAtPath:[[calculatorCopy stringByAppendingPathComponent:@"Contents"] stringByAppendingPathComponent:@"PkgInfo"] error:&removeError]) {
if (![[NSFileManager defaultManager] removeItemAtURL:[[calculatorCopy URLByAppendingPathComponent:@"Contents"] URLByAppendingPathComponent:@"PkgInfo"] error:&removeError]) {
XCTFail(@"Failed to remove file in calculator copy with error: %@", removeError);
}
self.calculatorCopyPath = calculatorCopy;

self.calculatorCopyURL = calculatorCopy;
}

- (void)setupInvalidSignedApp
{
NSError *error = nil;
NSString *tempDir = [self.notSignedAppPath stringByDeletingLastPathComponent];
NSString *signedAndInvalid = [tempDir stringByAppendingPathComponent:@"invalid-signed.app"];
if ([[NSFileManager defaultManager] fileExistsAtPath:signedAndInvalid]) {
[[NSFileManager defaultManager] removeItemAtPath:signedAndInvalid error:NULL];
NSString *tempDir = [self.notSignedAppURL URLByDeletingLastPathComponent];
NSString *signedAndInvalid = [tempDir URLByAppendingPathComponent:@"invalid-signed.app"];

if ([[NSFileManager defaultManager] fileExistsAtURL:signedAndInvalid]) {
[[NSFileManager defaultManager] removeItemAtURL:signedAndInvalid error:NULL];
}
if ([[NSFileManager defaultManager] copyItemAtPath:self.notSignedAppPath toPath:signedAndInvalid error:&error]) {
self.invalidSignedAppPath = signedAndInvalid;
if ([self codesignAppPath:self.invalidSignedAppPath]) {
NSString *fileInAppBundleToRemove = [self.invalidSignedAppPath stringByAppendingPathComponent:@"Contents/Resources/test_app_only_dsa_pub.pem"];
if (![[NSFileManager defaultManager] removeItemAtPath:fileInAppBundleToRemove error:&error]) {
if ([[NSFileManager defaultManager] copyItemAtURL:self.notSignedAppURL toPath:signedAndInvalid error:&error]) {
self.invalidSignedAppURL = signedAndInvalid;
if ([self codesignAppURL:self.invalidSignedAppURL]) {
NSString *fileInAppBundleToRemove = [self.invalidSignedAppURL URLByAppendingPathComponent:@"Contents/Resources/test_app_only_dsa_pub.pem"];
if (![[NSFileManager defaultManager] removeItemAtURL:fileInAppBundleToRemove error:&error]) {
NSLog(@"Failed to remove %@ with error %@", fileInAppBundleToRemove, error);
}
}
else {
NSLog(@"Failed to codesign %@", self.invalidSignedAppPath);
NSLog(@"Failed to codesign %@", self.invalidSignedAppURL);
}
}
else {
NSLog(@"Failed to copy %@ to %@ with error %@", self.notSignedAppPath, signedAndInvalid, error);
NSLog(@"Failed to copy %@ to %@ with error %@", self.notSignedAppURL, signedAndInvalid, error);
}
}

Expand All @@ -166,7 +161,7 @@ - (BOOL)unzip:(NSString *)zipPath toPath:(NSString *)destPath
task.launchPath = @"/usr/bin/unzip";
task.currentDirectoryPath = destPath;
task.arguments = @[zipPath];

[task launch];
[task waitUntilExit];
success = (task.terminationStatus == 0);
Expand All @@ -178,7 +173,7 @@ - (BOOL)unzip:(NSString *)zipPath toPath:(NSString *)destPath
return success;
}

- (BOOL)codesignAppPath:(NSString *)appPath
- (BOOL)codesignAppURL:(NSString *)appPath
{
BOOL success = NO;
@try
Expand Down Expand Up @@ -207,16 +202,16 @@ - (void)testUnsignedApp

- (void)testValidSignedApp
{
XCTAssertTrue([SUCodeSigningVerifier bundleAtURLIsCodeSigned:self.validSignedAppPath], @"App expected to be code signed");
XCTAssertTrue([SUCodeSigningVerifier bundleAtURLIsCodeSigned:self.validSignedAppURL], @"App expected to be code signed");

NSError *error = nil;
XCTAssertTrue([SUCodeSigningVerifier codeSignatureIsValidAtBundleURL:self.validSignedAppPath error:&error], @"signature should be valid");
XCTAssertTrue([SUCodeSigningVerifier codeSignatureIsValidAtBundleURL:self.validSignedAppURL error:&error], @"signature should be valid");
XCTAssertNil(error, @"error should be nil");
}

- (void)testValidSignedCalculatorApp
{
NSString *appPath = CALCULATOR_PATH;
NSURL *appPath = [NSURL fileURLWithPath:CALCULATOR_PATH];
XCTAssertTrue([SUCodeSigningVerifier bundleAtURLIsCodeSigned:appPath], @"App expected to be code signed");

NSError *error = nil;
Expand All @@ -227,29 +222,32 @@ - (void)testValidSignedCalculatorApp
- (void)testValidMatchingSelf
{
NSError *error = nil;
XCTAssertTrue([SUCodeSigningVerifier codeSignatureAtBundleURL:CALCULATOR_PATH matchesSignatureAtBundleURL:CALCULATOR_PATH error:&error], @"Our valid signed app expected to having matching signature to itself");
NSURL *appPath = [NSURL fileURLWithPath:CALCULATOR_PATH];

XCTAssertTrue([SUCodeSigningVerifier codeSignatureAtBundleURL:appPath matchesSignatureAtBundleURL:appPath error:&error], @"Our valid signed app expected to having matching signature to itself");
}

- (void)testValidMatching
{
// We can't test our own app because matching with ad-hoc signed apps understandably does not succeed
NSError *error = nil;
XCTAssertTrue([SUCodeSigningVerifier codeSignatureAtBundleURL:CALCULATOR_PATH matchesSignatureAtBundleURL:self.calculatorCopyPath error:&error], @"The calculator app is expected to have matching identity signature to its altered copy");
NSURL *appPath = [NSURL fileURLWithPath:CALCULATOR_PATH];
XCTAssertTrue([SUCodeSigningVerifier codeSignatureAtBundleURL:appPath matchesSignatureAtBundleURL:self.calculatorCopyURL error:&error], @"The calculator app is expected to have matching identity signature to its altered copy");
}

- (void)testInvalidMatching
{
NSString *appPath = CALCULATOR_PATH;
NSURL *appPath = [NSURL fileURLWithPath:CALCULATOR_PATH];
NSError *error = nil;
XCTAssertFalse([SUCodeSigningVerifier codeSignatureAtBundleURL:appPath matchesSignatureAtBundleURL:self.validSignedAppPath error:&error], @"Calculator app bundle expected to have different signature than our valid signed app");
XCTAssertFalse([SUCodeSigningVerifier codeSignatureAtBundleURL:appPath matchesSignatureAtBundleURL:self.validSignedAppURL error:&error], @"Calculator app bundle expected to have different signature than our valid signed app");
}

- (void)testInvalidSignedApp
{
XCTAssertTrue([SUCodeSigningVerifier bundleAtURLIsCodeSigned:self.invalidSignedAppPath], @"App expected to be code signed, but signature is invalid");
XCTAssertTrue([SUCodeSigningVerifier bundleAtURLIsCodeSigned:self.invalidSignedAppURL], @"App expected to be code signed, but signature is invalid");

NSError *error = nil;
XCTAssertFalse([SUCodeSigningVerifier codeSignatureIsValidAtBundleURL:self.invalidSignedAppPath error:&error], @"signature should not be valid");
XCTAssertFalse([SUCodeSigningVerifier codeSignatureIsValidAtBundleURL:self.invalidSignedAppURL error:&error], @"signature should not be valid");
XCTAssertNotNil(error, @"error should not be nil");
}

Expand Down

0 comments on commit c7a7704

Please sign in to comment.