A Quick Look plug-in for Provisioning

As every iOS developer knows, when your provisioning gets messed up, your life becomes a living hell. I don’t even want to think about how many millions of man hours have been wasted getting broken projects working again.

The root of the problem is always the .mobileprovision files that are kept in your Library > MobileDevice > Provisioning Profiles folder. The file either references a certificate that has expired or a device that no longer exists. There can also be issues with the entitlements that are contained in the profile when Team and App IDs don’t match.

A large part of the problem is that this file is not directly readable in a text editor like all the other parts of our Xcode projects. The file is encoded in the Cryptographic Message Syntax (CMS) described in RFC 3852.

After doing a bit of research, I found that decoding the payload of this file format is very simple thanks to some helpful functions in Apple’s Security framework. And once decoded, these .mobileprovision files contain nothing more than Property List (.plist) with a lot of useful debugging information.

I had previously been using a Quick Look plug-in from MacMation, but that site’s gone offline and the plug-in no longer worked in Mavericks. I had originally thought the problems on Mavericks were due to the new code signing requirements, but the root of the issue was that the content type UTI changed from com.apple.iphone.mobileprovision to just com.apple.mobileprovision so Quick Look ignored the old plug-in.

Eventually, I decided to write my own Quick Look plug-in and add a bunch of new stuff that I had been wanting to display:

  • Developer certificates: Making it easier to verify that your keychain items match what’s in the profile.
  • Provisioning Profile UUID: When someone on the project team checks in a new Provisioning Profile in the Build Settings, the only information you have is that UUID of that new file. Showing the UUID lets you find the right match.
  • Entitlements: Checking the Push Notification environment, ubiquity container identifiers, and keychain access groups is essential for any app that uses Apple’s services.
  • Links: Whenever the provisioning is broken you spend a lot of time in various sections of the Dev Center. Why not make it easy to get there?

The results of a few days work can be found on GitHub. If you’re lazy like I am, just download the .qlgenerator file and pop it in your Library > QuickLook folder. To get Quick Look to recognize the new plug-in you’ll need to either logout or poke Quick Look from the command line:

$ qlmanage -r

While you’re at the command line, do this to allow text to be copied from any Quick Look plug-in:

$ defaults write com.apple.finder QLEnableTextSelection -bool TRUE
$ killall Finder

(Macworld has more info about this nice hidden setting. Being able to copy text from a PDF preview is pretty damn handy!)

The next time you’re stuck in the Fifth Circle of Provisioning Hell, this simple plug-in may just bring you back to life. Viva!

Mac App Store Receipts and Mavericks

The storeagent and I aren’t getting along too well these days.

We’re in the process of getting a new release of xScope ready for release. As a developer tool, we’ve been compatible with Mavericks for several months now, but there are some minor bug fixes that we’d like to get out before the new version of OS X ships.

As you might be aware, this is the first time I’ve done a build on Mavericks itself. Things haven’t exactly been smooth sailing.

Today’s revelation is how storeagent creates the /Contents/_MASReceipt/receipt file in Mavericks. It’s subtly different, and will confuse the heck out of you until you understand what’s going on.

For the past few days, I’ve been testing a beta release of the .pkg using the standard command:

sudo installer -store -pkg /tmp/xScope.pkg -target /

This version had a CFBundleShortVersionString of “3.6.2b1”. The installer and receipt checking code was working great.

Until I did the final build and used the version string “3.6.2”. I got this message after I double-clicked the app and entered my Test User Apple ID:

After checking the code signing, bundle IDs and all other parts of the app, I finally fired up the debugger and discovered that the receipt validation code was failing when checking receipt attribute type 3, the Application version field (in Table 1-1).

After decrypting and checking the receipt payload, the value was “3.6.2b1” not the version I just installed. Where did this old version number come from? Why did following the advice in the dialog and deleting the app not fix the problem. How come this old receipt kept showing up no matter what I did?

Receipts from older versions had never been a problem in previous versions of OS X, so there must be some new behavior in Mavericks. And it took me almost a whole day to figure out that new behavior.

It turns out that storeagent is doing some kind of in-memory cache of receipts that have been downloaded from iTunes. Since a network connection is needed to retrieve the receipt, keeping it around would prevent a little bit of network traffic. In previous versions, the receipt was presumably recreated each time it was requested, so you always had a fresh copy.

The workaround is fairly simple. It even gives me a bit of pleasure at this point:

$ killall -KILL storeagent

You’ll need to delete the app at this point and re-install it using:

$ sudo installer -store -pkg YourApp.pkg -target /

When you relaunch your app, you’ll see the Apple ID login dialog. Since storeagent is launched on demand by launchd, a new process will be started at this point. After entering your Test User credentials, a new, and valid, receipt will be written into the _MASReceipt folder.

One could imagine this caching of receipt data being a problem with apps that are downloaded from the App Store. If someone never reboots between two versions of the same app being “Ready for Sale”, it may trigger the same problem. I have no way to test this hypothesis.

For any Apple folks that might be reading, here you go: rdar://problem/15283740

Code Signing and Mavericks

The Change

Very simply put, you can no longer sign a bundle (like your .app) if any nested bundle in that package is unsigned. These nested bundles are things like helper executables, embedded frameworks, plug-ins and XPC services.

The result is that you’ll need to update your Xcode projects as soon as you start building on 10.9. It’s taken me several days to understand what these changes are, and with the help of Perry Kiehtreiber on the developer forums, I’d like to share what I’ve learned.

(Yes, I realize this essay is going to break the NDA, but since Apple is asking us to submit apps for Mavericks, I want as many developers as possible to avoid the utter confusion I faced earlier this week.)

The Effect

So what happens when you do your first app build on 10.9 using Xcode 5.0.1? If you embed a framework that’s unsigned, like the very popular Sparkle.framework, you’ll see a message during the final CodeSign build phase:

CodeSign build/Release/xScope.app
    cd /Users/craig/Projects/Mac/xScope
    setenv CODESIGN_ALLOCATE /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/codesign_allocate
    Using code signing identity "Developer ID Application: The Iconfactory"
    /usr/bin/codesign --force --sign D2A3FE1814B0BA31B1924F1C3C3B5C89643FBED5 --requirements =designated\ =>\ anchor\ apple\ generic\ \ and\ identifier\ \"xScope\"\ and\ ((cert\ leaf[field.1.2.840.113635.100.6.1.9]\ exists)\ or\ (\ certificate\ 1[field.1.2.840.113635.100.6.2.6]\ exists\ and\ certificate\ leaf[field.1.2.840.113635.100.6.1.13]\ exists\ \ and\ certificate\ leaf[subject.OU]\ =\ \"RYQWBTQRPT\"\ )) /Users/craig/Projects/Mac/xScope/build/Release/xScope.app
/Users/craig/Projects/Mac/xScope/build/Release/xScope.app: code object is not signed at all
In subcomponent: /Users/craig/Projects/Mac/xScope/build/Release/xScope.app/Contents/Frameworks/Sparkle.framework
Command /usr/bin/codesign failed with exit code 1

** BUILD FAILED **

The codesign command is reporting that “code object is not signed at all” and Xcode is adding the “In subcomponent” to tell you which framework is at fault (it could just have easily been HockeyApp or any other third-party framework you use.)

So how do you go about fixing this?

The Wrong Way

In the past, many developers have relied on codesign‘s --deep option to make sure the entire bundle is signed. Specifying this option in “Other Code Signing Flags” will get rid of the error during the build, but all you’re doing is just postponing the pain.

The reason is that --deep recursively signs the nested bundles. As it does this, it applies the parameters for the top-level bundle to all the nested bundles. Things like your app’s entitlements will cause the resulting bundles to not be valid.

In fact, if you try to download and install the resulting app, Gatekeeper will notify your customers that your app is damaged and can’t be opened, with a default button to move it to the Trash:

You’ll see the same thing if you check the binary using the command line:

$ spctl --verbose=4 --assess --type execute build/Release/xScope.app
build/Release/xScope.app: a sealed resource is missing or invalid

The Right Way

What’s the right way to make sure the embedded framework is correctly signed? The answer is to add another Build Phase to your target.

If you’re embedding frameworks, you’ll have a “Copy Files” phase that moves things like Sparkle.framework into the Frameworks destination. Just after this Build Phase, add a Run Script with the following shell commands:

LOCATION="${BUILT_PRODUCTS_DIR}"/"${FRAMEWORKS_FOLDER_PATH}"
IDENTITY="Developer ID Application: The Iconfactory"
codesign --verbose --force --sign "$IDENTITY" "$LOCATION/Sparkle.framework/Versions/A"

This short script tells Xcode to sign the framework that’s just been copied into the build product. In this case, it’s using the Developer ID for Gatekeeper. If you were doing a build for the Mac App Store you’d use your “3rd Party Mac Developer Application” identity. Add a codesign command for every framework you use.

If you have other embedded code, such as helper executables, plug-ins or XPC services, you’ll need to sign them appropriately after copying them into your app bundle.

Updated October 18th, 2013: Another alternative is to set the code signing identity in the Build Settings of the frameworks you’re building from source. The trick here is that the identity of the framework needs to match the identity of the app itself. You can’t have have an App Store distribution identity for the framework and a Developer ID for the app. I found it much easier to explicitly re-sign the frameworks than to pass configuration settings from MyApp.xcodeproj to MyFramework.xcodeproj. It’s also easier to manage because the project changes are the same for binary-only frameworks (like Sparkle) and frameworks we build from source (like Chameleon).

The Checks

You’ll want to do a quick check of the build product before uploading it to either your website or iTunes Connect. The first thing you’ll want to do is check the signed bundle meets its designated requirement:

$ codesign --verify --verbose=4 build/Release/xScope.app
--validated:/Users/craig/Projects/Mac/xScope/build/Release/xScope.app/Contents/Frameworks/Sparkle.framework/Versions/Current/.
build/Release/xScope.app: valid on disk
build/Release/xScope.app: satisfies its Designated Requirement

If there’s a problem, you’ll see a message that the app “does not satisfy its designated Requirement”. To view information about the signed code or the designated requirements, you can use these commands:

$ codesign --display --verbose=4 build/Release/xScope.app
$ codesign --display --verbose=4 build/Release/xScope.app/Contents/Frameworks/Sparkle.framework
$ codesign --display --requirements - --verbose=4 build/Release/xScope.app
$ codesign --display --requirements - --verbose=4 build/Release/xScope.app/Contents/Frameworks/Sparkle.framework

If this is a build you’ll be uploading to your website, you’ll want to make sure it will be accepted by Gatekeeper (and not display the “damaged” dialog.) Use spctl to do this:

$ spctl --verbose=4 --assess --type execute build/Release/xScope.app
build/Release/xScope.app: accepted
source=Developer ID

If this is an App Store build, you MUST check the .pkg file that gets uploaded to iTunes Connect (see the next section and you’ll see why I say MUST.) If you use productbuild to create the package manually, you’ll already have a .pkg file to test.

For those of you who submit archives directly from Xcode, you can generate the .pkg file using the command line:

$ xcodebuild -exportArchive -exportFormat PKG -archivePath /path/to/your.xcarchive -exportPath /tmp/CHOCKS -exportSigningIdentity "3rd Party Mac Developer Application: CHOCK LOCK INK” -exportInstallerIdentity "3rd Party Mac Developer Installer:  CHOCK LOCK INK"

You can find the path to your .xcarchive by selecting it in the Organizer and then using the Editor > Show in Finder menu item. The command above will create a /tmp/CHOCKS.pkg. Yes, you now have CHOCKS PACKAGE IF YOU KNOW WHAT I MEAN

(A quick side note, if you use xcodebuild, it got a lot of love in Mavericks. Make sure to check out the man page.)

To check out CHOCKS.pkg, run the installer with the -store option:

$ sudo installer -store -pkg /tmp/CHOCKS.pkg -target /
installer: Note: running installer as an admin user (instead of root) gives better Mac App Store fidelity
installer: CHOCKS.pkg has valid signature for submission: 3rd Party Mac Developer Installer: The Iconfactory
installer: Installation Check: Passed
installer: Volume Check: Passed
installer: Bundle com.artissoftware.mac.xScope will be installed to /Applications/xScope.app
installer: Starting install
installer: Install 0.0% complete
installer: Install 13.8% complete
installer: Install 22.2% complete
installer: Install 47.6% complete
installer: Install 88.3% complete
installer: Install 100.0% complete
installer: Finished install

Now, sign out of the App Store and launch the app that was just installed in your Applications folder. If everything is OK, you’ll see the prompt for your Apple ID and a receipt will be written in the app’s _MASReceipt folder.

But not always.

(For more information on testing installer packages, check out the Testing section in my Mac App Store Guide.)

The Suckage

After being installed for the first time, some apps never get a receipt when they are launched on Mavericks. The app starts up, sees that there’s no receipt in /Contents/_MASReceipt and signals that it’s missing by exiting with a 173 code. Normally, storeagent will recognize this and prompt for an Apple ID. After valid credentials are provided, the receipt is written and the app is launched again.

Several developers, myself included, have noticed that after exiting with a 173, only the following is logged in the console:

Oct 17 11:59:03 Myrtle.local storeagent[72031]: Unsigned app (/Applications/Twitterrific.app).

If this happens to you, it seems your only course of action is to not validate the receipt. Your code will launch fine if you never return a 173. Which, of course, sucks because it’s then trivial to pirate your the app.

For any Apple folks that might be reading this, check out the Radar: rdar://problem/15254213

Updated October 18th, 2013: Developers that are doing their builds on 10.8 also need to watch out for this problem. As a workaround, I tried building the product on 10.8.4 using Xcode 5.0. The resulting .pkg exhibited the same behavior at launch time as the one created with the Xcode GM on Mavericks.

The Workarounds

Xcode sometimes has problems generating a valid designated requirement. When you check the designated requirement, you might see this:

$ codesign --verify --verbose=1 build/Release/Twitterrific.app
build/Release/Twitterrific.app: valid on disk
build/Release/Twitterrific.app: does not satisfy its designated Requirement

$ codesign --display --requirements - build/Release/Twitterrific.app
Executable=/Users/craig/Desktop/BugReport/Ostrich/build/Release/Twitterrific.app/Contents/MacOS/Twitterrific
designated => anchor apple generic and identifier Twitterrific and (certificate leaf[field.1.2.840.113635.100.6.1.9] /* exists */ or certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = RYQWBTQRPT)

If you look closely, you’ll see that the identifier used for the requirement is incorrect: it should be com.iconfactory.Twitterrific, not just Twitterrific. The workaround for this bug is simply to set the identifier explicitly in your Build Settings. In our case, we added --identifier com.iconfactory.Twitterrific to Other Code Signing Flags.

Updated October 18th, 2013: It looks like this bug happens when you precompile your Info.plist. Thanks to Chris Liscio for verifying that problem. Make sure to dupe it, if you’re affected!

As to why you’d want to precompile your Info.plist, there are two good reasons.

The End

There you have it: a short summary of my last three days of confusion caused by new Gatekeeper requirements, issues with Xcode and bugs in Mavericks. Hopefully, this essay will save you some of that same agony.

Sonderklasse

Let’s talk about cars for a second.

If you’re driving a car manufactured in the past five years, it’s likely it has anti-lock brakes. A standard feature at this point in time, but who came up with it first?

Mercedes-Benz first introduced it on the S-Class line back in 1978. It was a revolutionary technology and the first hint of how digital electronics would change the course of the automotive industry.

The S-Class pioneered many other safety innovations: crash crumple zones, air bags and traction control are a few of the most notable. This line has also become synonymous with comfort and luxury: it was the first Mercedes to be available with an automatic transmission. There’s even an armored version with a customized crocodile, gold and birch interior!

It’s clear this car is in a class by itself: “Sonderklasse”

“S-Class” is an anglicisation of “”S-Klasse,” a German abbreviation of “Sonderklasse,” which means “special class” (in the sense of “a class of its own”). In automotive terms thus refers to “a specially outfitted car”.

The current S600 model sports a 5.5L twin turbo V12 motor with a 7-speed automatic transmission. Enough power to propel a 4,950 lb vehicle from 0 to 60 mph in just 4.5 seconds. And that’s before AMG gets their hands on it. Impressive automotive technology, to be sure.

More importantly, these special cars have been recognized as a driving force behind the company’s success.

And now…

Another premium technology brand has an S-Class product: iPhone 5s.

“Craftsmanship”, “Power”, “Safety & Security”, “Ahead of its time”. Are we talking about a car or a phone?

Look at the words that dominate the iPhone 5s features page: Forward thinking. That’s a strategy that’s worked superbly at Mercedes-Benz for almost 60 years. I suspect Apple will get a pretty good run out of it, too.

Fingerprints

It looks like my hunch about the iPhone invite was right: new phones are likely to have “silver rings” that are fingerprint sensors embedded into the home button.

So what does this mean? Most people assume that it’s just going to be easier to access your home screen (without entering a passcode.) But I think it goes much deeper than that.

iCloud services are a huge part of Apple’s next decade. Everything the company is doing these days has some kind of connection to data that is stored remotely. They’re investing heavily in new data centers.

And anytime you want to access this data, you’re logging into iCloud. Wouldn’t it be great if you could skip the part where you have to type in your Apple ID?

It’s clear to me that your unique fingerprint will be tied to your unique Apple ID. Once this connection between your physical and online presences is established, some very interesting things become possible. Let’s take a look at a few things I think might happen:

Protecting access to apps

From the beginning, I’ve wanted a way to protect my personal information when sharing a device with friends and family. But any secure solution to that problem would be a pain in the butt. Typing a password before launching an app? No thanks!

But imagine if opening your favorite Twitter app only required a fingerprint scan before proceeding. Everyone’s favorite Twitter prank would thankfully die. And more importantly, we’d all feel a lot better about using things like online banking apps.

Corporate security

Most corporate networks are protected by VPN. The profiles that enable this network configuration often specify that a user must use a passcode lock. And it’s rarely a simple passcode. And it kicks in immediately.

Imagine needing to type in a eight character password with letters and numerals just to check the current weather. That’s a reality for millions of people who use their device for both personal and business tasks.

A fingerprint scanner that avoids this complex password will sell a lot of devices.

Multiple accounts

There are many scenarios where you want to let someone do whatever they want with your personal device: a partner providing directions while you drive, a kid playing games in a waiting room, your parents looking at vacation photos. All these people have something different than you: a fingerprint.

Entering a login and password has always seemed out of place in the simplified world of iOS. But detecting which account to use when tapping on the home button actually makes it easier for members of your family to use your personal device: they don’t even have to slide to unlock.

And once everyone has their own personal space on the device, no one can mess with it. This is important in many contexts: even something simple like a game has sensitive information as soon as a sibling comes along and screws up high scores or play position.

Borrowing devices

Most of us backup our data to iCloud. That data is restored to a device when it’s first put into service or if something goes wrong.

Now imagine if you had the ability to restore your data onto any device with the touch of your finger. Borrow an iPad and make it yours instantly. Businesses that strive to make a customer feel at home, like hotels and airlines, would love this capability.

Personal identification

If you think Apple is going to give developers access to this biometric information, think again. Google would love this data, so you know it’s not going to happen.

Slowly but surely

Don’t expect all these things to appear on September 10th. Apple will start out simply and continue to improve the software that uses this new sensor. That’s how they roll.

Acknowledgments: The genesis of these ideas came from a conversation with my colleague Sean Heber. He’s the one that first made the connection between iCloud and your finger. Thanks also go to Ryan Jones for the links about the sensor.