Mac App Store receipt validation revisited

By admin
Feedback Assistant Boycott


Mac App Store
ORG

receipt validation revisited


November 8 2023
DATE


Michael Tsai’s
PERSON

encyclopedic blog has discussed issues with

Mac App Store
ORG

receipt validation in

2019
DATE

and again in

2022
DATE

. In summary,

Apple
ORG

‘s old sample code for developers was broken, some developers tried to fix it, and

Apple
ORG

later posted new sample code (at the same URL). However, I’ve recently run into a case that seems to call into question all extant sample code for

Mac App Store
ORG

receipt validation. Someone purchased my app

Link Unshortener
PERSON

but was unable to launch it. The customer also mentioned being unable to launch another developer’s

Mac App Store
ORG

app,

Magnet
ORG

. This suggested a problem with receipt validation. I learned that the ethernet port of the customer’s Mac was fried as a result of electrical damage from a lightning strike. The

Mac
ORG

‘s motherboard was replaced, but afterward the customer still couldn’t launch

Magnet
ORG

, and now they couldn’t launch Link Unshortener either. It turns out that the

Mac
ORG

‘s ethernet port is now en11 rather than en0 .

Apple
ORG

‘s old sample code checked only en0 , and

Apple
ORG

‘s new sample code checks only en0 and

en1
ORG

, so that technique won’t work. And the technique suggested by

Chris Liscio
PERSON

won’t work, because querying for kIOPrimaryInterface returned no results! The customer’s

Mac
ORG

reported having no primary ethernet interface.

My solution was to query all built-in ethernet interfaces—in technical terms,

kIOBuiltin
PRODUCT

devices of

kIOEthernetInterfaceClass
ORG

—and attempt to validate each interface’s

MAC
ORG

address with the

App Store
ORG

receipt until a match was found. This might be the same technique suggested by

Paulo Andrade
PERSON

, but that blog post contains no sample code.

Below is a snippet from my new

Mac App Store
ORG

receipt validation code.


mach_port_t master_port
ORG

;

kern_return_t kernResult
PERSON

=

IOMasterPort
ORG

( MACH_PORT_NULL, &master_port ); if ( kernResult != KERN_SUCCESS ) return

EXIT_FAILURE
PERSON

; CFMutableDictionaryRef matchingDict =

IOServiceMatching(kIOEthernetInterfaceClass
ORG

); if ( matchingDict == NULL ) return

EXIT_FAILURE
PERSON

; CFMutableDictionaryRef propertyMatch = CFDictionaryCreateMutable( kCFAllocatorDefault,

0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks
ORG

); CFDictionarySetValue( propertyMatch, CFSTR(kIOBuiltin), kCFBooleanTrue ); CFDictionarySetValue( matchingDict,

CFSTR(kIOPropertyMatchKey
PRODUCT

), propertyMatch );

CFRelease
PERSON

( propertyMatch );

io_iterator_t iterator
ORG

; kernResult = IOServiceGetMatchingServices( master_port, matchingDict, &iterator ); // This actually releases matchingDict because CF_RELEASES_ARGUMENT if ( kernResult != KERN_SUCCESS ) return

EXIT_FAILURE
PERSON

;

BOOL hasMatch
PERSON

= NO; do { io_object_t service = IOIteratorNext( iterator ); if ( service ==

IO_OBJECT_NULL
PERSON

) break; io_object_t parentService;

kernResult = IORegistryEntryGetParentEntry
ORG

( service,

kIOServicePlane, &parentService
ORG

); if (

kernResult
PERSON

== KERN_SUCCESS ) { CFDataRef newMacAddress = (

CFDataRef)IORegistryEntryCreateCFProperty
PERSON

( parentService, CFSTR( kIOMACAddress ), kCFAllocatorDefault,

0
CARDINAL

); if ( newMacAddress != NULL ) { /*

Validate
ORG


MAS
ORG

receipt and set hasMatch = YES if valid. */ CFRelease( newMacAddress ); } IOObjectRelease( parentService ); } IOObjectRelease( service ); } while ( !

hasMatch
PERSON

); IOObjectRelease( iterator );

I released a Link Unshortener update with the new code, which fixed my customer’s problem.

The Mac App Store
ORG

receipt now validates, and the app launches. Moreover, I’ve received no reports of failures from other customers. So far, so good!

By the way, my

Mac App Store
ORG

receipt validation code doesn’t require compiling and linking OpenSSL. To avoid that, I wrote a receipt parser using

Apple
ORG

‘s built-in

CommonCrypto
ORG

and Security frameworks. I won’t post the full source code here, but if any

Mac
ORG

developers are interested, let me know. My code works only for upfront paid apps, however, not for In

App Purchases
ORG

.

Feedback Assistant Boycott