Compare commits

..

5 Commits

Author SHA1 Message Date
Hannes Oud 4dd74e61bb Merge pull request #78 from structuredpath/enhancement/useLocalPackageInWorkspace
Use local copy of the library for demo projects
2021-12-17 17:04:17 +01:00
Lukas Kubanek cca79b7d2f Use local copy of the library for demo projects
The Xcode workspace was configured to use the upstream version of the AppReceiptValidator package, which wouldn’t allow for testing local changes made to the package.
2021-12-17 12:21:07 +01:00
Michael Schwarz 171c84ec5c Merge pull request #77 from IdeasOnCanvas/enhancement/fixParsingProvisioningType
Fix parsing of provisioning type (unofficial receipt parts)
2021-12-17 12:14:27 +01:00
Hannes Oud 91e300cf49 Add tests for unofficialReceipt provisioning type 2021-12-16 18:17:25 +01:00
Hannes Oud 192b0102cf Fix parsing of unofficial receipt provisioning field 2021-12-16 18:17:02 +01:00
4 changed files with 49 additions and 60 deletions
@@ -7,10 +7,10 @@
objects = {
/* Begin PBXBuildFile section */
D1150C78274BA3AD007FA109 /* AppReceiptValidator in Frameworks */ = {isa = PBXBuildFile; productRef = D1150C77274BA3AD007FA109 /* AppReceiptValidator */; };
D1150C79274BA3AD007FA109 /* AppReceiptValidator in Embed Frameworks */ = {isa = PBXBuildFile; productRef = D1150C77274BA3AD007FA109 /* AppReceiptValidator */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
D1150C7B274BA3B1007FA109 /* AppReceiptValidator in Frameworks */ = {isa = PBXBuildFile; productRef = D1150C7A274BA3B1007FA109 /* AppReceiptValidator */; };
D1150C7C274BA3B1007FA109 /* AppReceiptValidator in Embed Frameworks */ = {isa = PBXBuildFile; productRef = D1150C7A274BA3B1007FA109 /* AppReceiptValidator */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
80AB3E2F276CA8E100C4AB61 /* AppReceiptValidator in Frameworks */ = {isa = PBXBuildFile; productRef = 80AB3E2E276CA8E100C4AB61 /* AppReceiptValidator */; };
80AB3E30276CA8E100C4AB61 /* AppReceiptValidator in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 80AB3E2E276CA8E100C4AB61 /* AppReceiptValidator */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
80AB3E32276CA8E500C4AB61 /* AppReceiptValidator in Frameworks */ = {isa = PBXBuildFile; productRef = 80AB3E31276CA8E500C4AB61 /* AppReceiptValidator */; };
80AB3E33276CA8E500C4AB61 /* AppReceiptValidator in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 80AB3E31276CA8E500C4AB61 /* AppReceiptValidator */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
D13E5B7D20331B9B001880F0 /* DropAcceptingTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D13E5B7C20331B9B001880F0 /* DropAcceptingTextView.swift */; };
D19095841F6000A40095729B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D19095831F6000A40095729B /* AppDelegate.swift */; };
D19095861F6000A40095729B /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D19095851F6000A40095729B /* ViewController.swift */; };
@@ -30,7 +30,7 @@
dstPath = "";
dstSubfolderSpec = 10;
files = (
D1150C7C274BA3B1007FA109 /* AppReceiptValidator in Embed Frameworks */,
80AB3E33276CA8E500C4AB61 /* AppReceiptValidator in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
@@ -41,7 +41,7 @@
dstPath = "";
dstSubfolderSpec = 10;
files = (
D1150C79274BA3AD007FA109 /* AppReceiptValidator in Embed Frameworks */,
80AB3E30276CA8E100C4AB61 /* AppReceiptValidator in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
@@ -72,7 +72,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
D1150C7B274BA3B1007FA109 /* AppReceiptValidator in Frameworks */,
80AB3E32276CA8E500C4AB61 /* AppReceiptValidator in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -80,7 +80,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
D1150C78274BA3AD007FA109 /* AppReceiptValidator in Frameworks */,
80AB3E2F276CA8E100C4AB61 /* AppReceiptValidator in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -160,7 +160,7 @@
);
name = "AppReceiptValidator Demo macOS";
packageProductDependencies = (
D1150C7A274BA3B1007FA109 /* AppReceiptValidator */,
80AB3E31276CA8E500C4AB61 /* AppReceiptValidator */,
);
productName = "AppReceiptValidator Demo macOS";
productReference = D19095811F6000A40095729B /* AppReceiptValidator Demo macOS.app */;
@@ -182,7 +182,7 @@
);
name = "AppReceiptValidator Demo iOS";
packageProductDependencies = (
D1150C77274BA3AD007FA109 /* AppReceiptValidator */,
80AB3E2E276CA8E100C4AB61 /* AppReceiptValidator */,
);
productName = "Demo iOS";
productReference = D1D6F4E41F5D691400E86FE1 /* AppReceiptValidator Demo iOS.app */;
@@ -224,7 +224,6 @@
);
mainGroup = D1D6F4921F5D67E600E86FE1;
packageReferences = (
D1150C73274BA2C8007FA109 /* XCRemoteSwiftPackageReference "AppReceiptValidator" */,
);
productRefGroup = D1D6F49C1F5D67E600E86FE1 /* Products */;
projectDirPath = "";
@@ -584,26 +583,13 @@
};
/* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */
D1150C73274BA2C8007FA109 /* XCRemoteSwiftPackageReference "AppReceiptValidator" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/IdeasOnCanvas/AppReceiptValidator";
requirement = {
branch = main;
kind = branch;
};
};
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
D1150C77274BA3AD007FA109 /* AppReceiptValidator */ = {
80AB3E2E276CA8E100C4AB61 /* AppReceiptValidator */ = {
isa = XCSwiftPackageProductDependency;
package = D1150C73274BA2C8007FA109 /* XCRemoteSwiftPackageReference "AppReceiptValidator" */;
productName = AppReceiptValidator;
};
D1150C7A274BA3B1007FA109 /* AppReceiptValidator */ = {
80AB3E31276CA8E500C4AB61 /* AppReceiptValidator */ = {
isa = XCSwiftPackageProductDependency;
package = D1150C73274BA2C8007FA109 /* XCRemoteSwiftPackageReference "AppReceiptValidator" */;
productName = AppReceiptValidator;
};
/* End XCSwiftPackageProductDependency section */
@@ -7,7 +7,7 @@
"state": {
"branch": null,
"revision": "6f36ef23becd7f9266ef6b026af4798996a1a8be",
"version": null
"version": "1.8.1"
}
},
{
@@ -154,34 +154,8 @@ private extension AppReceiptValidator {
guard let signatureData = signature.signatureData else { throw Error.receiptNotSigned }
guard let receiptData = pkcs7.mainBlock.findOid(.pkcs7data)?.parent?.sub?.last?.sub(0)?.rawValue else { throw Error.receiptNotSigned }
let rootCert1 = pkcs7.certificates[0]
let rootCert2: X509Certificate = try .init(data: appleRootCertificateData)
do {
func validateChain() {
let rootCert = SecCertificateCreateWithData(nil, appleRootCertificateData as CFData)
let receiptCerts = pkcs7.certificatesData.compactMap { SecCertificateCreateWithData(nil, $0 as CFData) }
let policy = SecPolicyCreateBasicX509()
var optionalTrust: SecTrust?
let status = SecTrustCreateWithCertificates([rootCert] as AnyObject,
policy,
&optionalTrust)
if status == errSecSuccess {
let trust = optionalTrust! // Safe to force unwrap now
SecTrustSetAnchorCertificates(trust, [receiptCerts] as CFArray)
var error: CFError?
print("Veryfing result: ", SecTrustEvaluateWithError(trust, &error))
print(error)
}
else {
print("error")
}
}
validateChain()
}
try self.verifyAuthenticity(x509Certificate: rootCert2, receiptData: receiptData, signatureData: signatureData)
let rootCert = pkcs7.certificates[0]
try self.verifyAuthenticity(x509Certificate: rootCert, receiptData: receiptData, signatureData: signatureData)
}
func verifyAuthenticity(x509Certificate: X509Certificate, receiptData: Data, signatureData: Data) throws {
@@ -190,10 +164,6 @@ private extension AppReceiptValidator {
guard let key = x509Certificate.publicKey?.secKey,
let algorithm = x509Certificate.publicKey?.secAlgorithm else { throw Error.receiptSignatureInvalid }
//
//
// guard SecTrustCreateWithCertificates(<#T##certificates: CFTypeRef##CFTypeRef#>, <#T##policies: CFTypeRef?##CFTypeRef?#>, <#T##trust: UnsafeMutablePointer<SecTrust?>##UnsafeMutablePointer<SecTrust?>#>)
//
var verifyError: Unmanaged<CFError>?
guard SecKeyVerifySignature(key, algorithm, receiptData as CFData, signatureData as CFData, &verifyError),
verifyError == nil else {
@@ -242,7 +212,7 @@ private extension AppReceiptValidator {
let items = receiptBlock.sub else { return .init(entries: []) }
let entries: [UnofficialReceipt.Entry] = items.compactMap { item in
guard let fieldType = (item.sub(0)?.value as? Data)?.uint64Value,
guard let fieldType = (item.sub(0)?.value as? Data)?.uint64ValueOrZero, // provisioning fieldtype pops up here as empty Data, so we use uint64ValueOrZero
KnownReceiptAttribute(rawValue: fieldType) == nil else { return nil }
let fieldValueString = item.sub(2)?.asString
@@ -428,3 +398,15 @@ extension X509PublicKey {
}
#endif
}
// MARK: - Data + Unofficial Receipt FieldTypes
private extension Data {
/// Decoded as by ASN1Decoder's Data.uint64Value extension, or as 0 if empty
var uint64ValueOrZero: UInt64? {
if self.isEmpty { return 0 }
return self.uint64Value
}
}
@@ -247,6 +247,27 @@ class AppReceiptValidatorTests: XCTestCase {
XCTAssertEqual(receipt, expected)
}
func testUnofficialProvisioningTypes() throws {
do {
guard let data = assertB64TestAsset(filename: "mindnode_ios_michaelsandbox_receipt1.b64") else { return }
let result = try receiptValidator.parseUnofficialReceipt(origin: .data(data))
XCTAssertEqual(result.unofficialReceipt.provisioningType, .known(value: .productionSandbox))
}
do {
guard let data = assertB64TestAsset(filename: "mindnode_ios_michaelsandbox_receipt2.b64") else { return }
let result = try receiptValidator.parseUnofficialReceipt(origin: .data(data))
XCTAssertEqual(result.unofficialReceipt.provisioningType, .known(value: .productionSandbox))
}
do {
guard let data = assertB64TestAsset(filename: "hannes_mac_mindnode_receipt.b64") else { return }
let result = try receiptValidator.parseUnofficialReceipt(origin: .data(data))
XCTAssertEqual(result.unofficialReceipt.provisioningType, .known(value: .production))
}
}
func testMindNodeiOSSandBoxReceipt2ParsingAndValidation() {
guard let data = assertB64TestAsset(filename: "mindnode_ios_michaelsandbox_receipt2.b64") else { return }