Wednesday, October 16, 2019

Receipt Validation and AirPlay 2

Chris Liscio:

I hear rumblings about some App Store receipt validation issues relating to MAC addresses on macOS Catalina. The commonly-used Apple sample code has busted logic that—in the presence of a strange condition on a (small?) number of systems—will fail to return a value.


I don’t know yet, but it manifests on my machine as a service match for both en0 as well as IOTimeSyncEthernetModernInterfaceAdapter (see attached screenshot.) The latter causes a second go-around in the while loop, causing the MAC address to get overwritten with NULL.

It makes no sense for Apple to provide buggy sample code for getting the MAC address when every app in the store needs to do this. With some other aspects of receipt validation, one could argue that you want each app to do it slightly differently to make them harder to crack. But the point of checking the MAC address is that you want to match it with the address provided by Apple when it generated the receipt. So you want to use the exact same logic they did.

Paul Haddad:

BTW I don’t think this is a Catalina issue, have seen reports of what sounds like this for several OS versions. Also seems to work if tested right after reboot, but breaks if tested later.

Chris Liscio:

The plot thickens!

After a reboot, my system no longer exhibits this “strange condition”.

Immediately after playing audio over AirPlay 2? BOOM—“strange condition”! 🤯

The “strange condition” appears to be the presence of IOTimeSyncEthernetModernInterfaceAdapter in ioreg.


Update (2019-10-22): Chris Liscio (tweet, James Thomson):

While playing audio using AirPlay 2, there are two devices that have a BSD Name equal to en0. Both the actual en0 interface, and a new device called IOTimeSyncEthernetModernInterfaceAdapter (or IOTimeSyncWiFiInterfaceAdapter, depending on your Mac) that is only present while AirPlay is active.


When copy_mac_address returns NULL, your receipt validation code fails, and probably results in your application calling exit(173) to ask the App Store for a new receipt. Unfortunately, a new receipt isn’t going to help, and you get stuck in a very strange loop.

For me, this resulted in the app repeatedly appearing & disappearing in the Dock for quite some time. Eventually, the system finally gave up and told me the app was “Damaged” and needed to be re-downloaded.


The keys to this alternate approach are as follows:

  1. It specifies the kIOEthernetInterfaceClass, which only matches network interfaces. (Before you ask—yes, this includes Wi-Fi adapters.)
  2. It also specifies that kIOPrimaryInterface is set to true, which matches the built-in, primary network interface.

Update (2021-10-20): Paulo Andrade:

In reality the device identifier for macOS is the MAC for the primary network interface, which might not actually be named en0. To be on the safe side, instead of trying to determine which interface is the primary, I just grab all the MACs on that Mac and attempt validation with each one. Problem solved! Right?

Well… not yet. There’s another issue I just encountered recently. The IOBSDNameMatching call to get an interface by name can actually return nil even when ifconfig shows an interface with that name. I haven’t been able to understand why this happens (it’s very rare), but on one occasion Vallum Firewall seemed to be the culprit and on another, a simple restart seemed to fix it.

I finally ended up with a solution based on Apple’s source code here. Instead of getting a list of interface names and then getting the MAC for each by name I just iterate all the interfaces irrespective of what they’re called and collect the MACs for each.

Comments RSS · Twitter

Leave a Comment