Skip to content

Commit

Permalink
Merge pull request #93 from IdeasOnCanvas/enhancement/addSHA256Tests
Browse files Browse the repository at this point in the history
Add test and implement sha256-signed receipts
  • Loading branch information
weichsel authored Aug 28, 2023
2 parents 4ab86e9 + 0630724 commit 439b963
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,13 @@
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES"
testExecutionOrdering = "random">
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D19095911F6000A40095729B"
BuildableName = "AppReceiptValidator Tests macOS.xctest"
BlueprintName = "AppReceiptValidator Tests macOS"
ReferencedContainer = "container:AppReceiptValidator.xcodeproj">
BlueprintIdentifier = "AppReceiptValidatorTests"
BuildableName = "AppReceiptValidatorTests"
BlueprintName = "AppReceiptValidatorTests"
ReferencedContainer = "container:..">
</BuildableReference>
</TestableReference>
</Testables>
Expand Down
1 change: 1 addition & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ let package = Package(
.copy("Resources/mindnode_ios_michaelsandbox_receipt2.b64"),
.copy("Resources/purchasing_experiments_sandbox_receipt.b64"),
.copy("Resources/not_a_receipt"),
.copy("Resources/mindnode_mac_sha256_receipt"),
.copy("Resources/frank4dd-cacert.der")
])
],
Expand Down
18 changes: 14 additions & 4 deletions Sources/AppReceiptValidator/AppReceiptValidator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ private extension AppReceiptValidator {
// TODO: Migrate this from Security.framework to BoringSSL/Cryptokit to allow compilation on Linux
#if !os(Linux)
guard let key = x509Certificate.publicKey?.secKey,
let algorithm = x509Certificate.publicKey?.secAlgorithm else { throw Error.receiptSignatureInvalid }
let algorithm = x509Certificate.secSignatureAlgorithm else { throw Error.receiptSignatureInvalid }

var verifyError: Unmanaged<CFError>?
guard SecKeyVerifySignature(key, algorithm, receiptData as CFData, signatureData as CFData, &verifyError),
Expand Down Expand Up @@ -424,14 +424,24 @@ extension X509PublicKey {
return SecKeyCreateWithData(publicKeyDerEncoded as CFData, attributes as CFDictionary, &error)
}

var secAlgorithm: SecKeyAlgorithm? {
guard let oid = self.algOid,
#endif
}

// MARK: - X509Certificate + SecKeyAlgorithm

extension X509Certificate {

#if !os(Linux)
var secSignatureAlgorithm: SecKeyAlgorithm? {
guard let oid = self.sigAlgOID,
let algorithm = OID(rawValue: oid) else { return nil }

switch algorithm {
// We only support RSA for now
case .rsaEncryption:
case .sha1WithRSAEncryption:
return .rsaSignatureMessagePKCS1v15SHA1
case .sha256WithRSAEncryption:
return .rsaSignatureMessagePKCS1v15SHA256
default:
return nil
}
Expand Down
56 changes: 56 additions & 0 deletions Tests/AppReceiptValidatorTests/AppReceiptValidatorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,62 @@ class AppReceiptValidatorTests: XCTestCase {
XCTAssertEqual(receipt, expected)
}

func testSHA256SignedReceipt() {
guard let data = assertTestAsset(filename: "mindnode_mac_sha256_receipt") else { return }

let parameters = AppReceiptValidator.Parameters.default.with {
$0.receiptOrigin = .data(data)
$0.deviceIdentifier = .init(macAddress: "f8:ff:c2:1e:91:82")!
}
let result = receiptValidator.validateReceipt(parameters: parameters)
let expected = Receipt(
bundleIdentifier: "com.ideasoncanvas.mindnode.macos",
bundleIdData: "DCBjb20uaWRlYXNvbmNhbnZhcy5taW5kbm9kZS5tYWNvcw==",
appVersion: "2023.2.2",
opaqueValue: "VmWS/KFzfC1svdKl/fE28w==",
sha1Hash: "qDMXlx3d0G20ClaveV6dpPPHDRg=",
originalAppVersion: "5.0",
receiptCreationDate: "2023-08-28T10:24:05Z",
expirationDate: nil,
inAppPurchaseReceipts: [
InAppPurchaseReceipt(
quantity: 1,
productIdentifier: "com.ideasoncanvas.mindnode.macos.iap.trial",
transactionIdentifier: "710000250371060",
originalTransactionIdentifier: "710000250371060",
purchaseDate: "2017-11-28T11:13:57Z",
originalPurchaseDate: "2017-11-28T11:13:57Z",
subscriptionExpirationDate: nil,
cancellationDate: nil,
webOrderLineItemId: nil
),
InAppPurchaseReceipt(
quantity: 1,
productIdentifier: "com.ideasoncanvas.mindnode.macos.iap.fullversionfree",
transactionIdentifier: "710000253893482",
originalTransactionIdentifier: "710000253893482",
purchaseDate: "2017-12-13T14:04:33Z",
originalPurchaseDate: "2017-12-13T14:04:33Z",
subscriptionExpirationDate: nil,
cancellationDate: nil,
webOrderLineItemId: nil
),
InAppPurchaseReceipt(
quantity: 1,
productIdentifier: "com.ideasoncanvas.mindnode.macos.subscription.yearly",
transactionIdentifier: "710000831465389",
originalTransactionIdentifier: "710000831465389",
purchaseDate: "2021-09-10T12:37:29Z",
originalPurchaseDate: "2021-09-10T12:37:34Z",
subscriptionExpirationDate: "2022-09-24T12:37:29Z",
cancellationDate: nil,
webOrderLineItemId: 710000353660114
)
]
)
XCTAssertEqual(expected, result.receipt)
}

func DISABLED_testiOSParsingPerformance() {
guard let data = assertB64TestAsset(filename: "mindnode_ios_michaelsandbox_receipt1.b64") else { return }

Expand Down
Binary file not shown.

0 comments on commit 439b963

Please sign in to comment.