Mac App Store receipt validation revisited

Created on November 12, 2023 at 11:10 am

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

Connecting to Connected... Page load complete