Category Archives: Mac App Store

Mac App Store Receipt Validation

When you develop a Mac app, particularly paid app, it is important to ensure that users install genuine copies of your app via the right channel. Apps distributed outside of the Mac App Store achieve this by issuing Licenses to users which they need to enter into the app before they can start using it. Apps distributed via the Mac App Store achieve this using Mac App Store receipt validation.

Every app that is downloaded from the Mac App Store is provided a receipt that resides in the app bundle at /Contents/_MASReceipt/receipt. The receipt is cryptographically signed ensuring that only Apple can create it. Developers are required to write code to validate the receipt which guarantees that the copy of the app is valid and installed via the Mac App Store. Without this check by developers, apps can be downloaded once and passed around to other users bypassing the Mac App Store. Recently, I integrated receipt validation in my Mac App. This post attempts to summarize the knowledge I acquired in the process.

Receipt validation can be done in two ways

  1. Validating with the Mac App Store: From the app, you can pass the installed receipt to your server which can perform the validation by communicating with Apple servers and notify the app about the validation result.
  2. Validating locally in the app: You can write the receipt validation code locally in the application code.

This post only covers validating receipts locally. For validating receipts with the Mac App Store, check this. It is recommended by Apple that receipt validation be performed as soon as the app is launched. The validation code should be added to the main() function before NSApplicationMain() call.

Validation Steps In Order

  1. Locate the receipt and verify that it is properly signed by Apple.
  2. Verify that the bundle identifier, version identifier strings in the receipt match the CFBundleIdentifier, CFBundleShortVersionString values respectively in the Info.plist file.
  3. Compute the hash of the GUID and verify that it matches the hash in the receipt.
  4. Note: The GUID is uniquely tied to the hardware on which the app is originally installed from the Mac App Store ensuring that copied apps don’t work due to GUID mismatch.

If all of the above steps pass, validation succeeds.

Handling Validation Failure

Sometimes it may happen that a valid install fails to write the Mac App Store receipt to the app bundle resulting in receipt validation failure when the app runs. In such cases, you should call exit with a status of 173. This exit status notifies the system that your application has determined that its receipt is invalid. At this point, the system attempts to obtain a valid receipt and may prompt for the user’s iTunes credentials.

The system relaunches the application if it successfully obtains a valid receipt. Otherwise it displays an error message to the user explaining the problem. You should not display any error message to the user on validation failure because this duty is delegated to the system. The system is responsible for trying to obtain a valid receipt or informing the user that the receipt is not valid.

Things To Remember

  • Don’t Localize Your Version Number

    If your application is localized, the CFBundleShortVersionString key should not appear in any of your application’s InfoPlist.strings files. The unlocalized value from your Info.plist file is stored in the receipt. Attempting to localize the value for this key can cause receipt validation to fail.

  • Protect Your Validation Check
    1. Inline the code for cryptographic checks instead of using the APIs provided by the system.
    2. Avoid simple code constructions that provide a trivial target for patching the application binary. For example, avoid writing code like
      if (failedValidation) {
              exit(173);
      }
          
    3. Use code obfuscation to avoid reverse engineering.
    4. Ensure that even if the exit function fails to terminate your application, your application stops running. You may use abort().

Testing Receipt Validation During Development Phase

In order to test your Mac app during the development phase, you need a valid receipt so that your application launches. To set this up, do the following

  1. Make sure you have Internet access so you can connect to Apple’s servers.
  2. Create a test user in iTunesConnect > Manage Users section.
  3. Launch your application by double-clicking on it.
  4. Your application fails to validate its receipt because there is no receipt present and exits with a status of 173.
  5. The system interprets the exit status and attempts to obtain a valid receipt by prompting you to enter your iTunes credentials. You should provide the test user’s (step 2) details here.
  6. Assuming your application signing certificate is valid, the system installs a valid receipt for the application.
  7. The system relaunches your application, and your application successfully validates the receipt.

Receipt validation is a crucial step in Mac app development process and I hope this post makes implementing it easier for someone. Here are some libraries to get you started in the right direction. GOOD LUCK AND GOOD LIFE!!!

Mac App Store Build Validations

I recently submitted my first Mac App to the Mac App Store. Before submission, I ran a bunch of validation steps on my final production ready app. Craig Hockenberry’s blog post made it much easier. Here are the key steps

  1. Launch Terminal app and cd to the dir where the .app file is located.
  2. Recursively finds all Mach-O bundles in the app bundle.
    $ find -H Myapp.app -print0 | xargs -0 file | grep "Mach-O"
    
    Myapp.app/Contents/Frameworks/CorePlot.framework/CorePlot:                                                  Mach-O 64-bit dynamically linked shared library x86_64
    
    Myapp.app/Contents/Frameworks/CorePlot.framework/Versions/A/CorePlot:                                       Mach-O 64-bit dynamically linked shared library x86_64
    Myapp.app/Contents/Frameworks/CrashReporter.framework/CrashReporter:                                        Mach-O universal binary with 2 architectures
    Myapp.app/Contents/Frameworks/CrashReporter.framework/CrashReporter (for architecture x86_64):	            Mach-O 64-bit dynamically linked shared library x86_64
    Myapp.app/Contents/Frameworks/CrashReporter.framework/CrashReporter (for architecture i386):		    Mach-O dynamically linked shared library i386
    Myapp.app/Contents/Frameworks/CrashReporter.framework/Versions/A/CrashReporter:                             Mach-O universal binary with 2 architectures
    Myapp.app/Contents/Frameworks/CrashReporter.framework/Versions/A/CrashReporter (for architecture x86_64):   Mach-O 64-bit dynamically linked shared library x86_64
    Myapp.app/Contents/Frameworks/CrashReporter.framework/Versions/A/CrashReporter (for architecture i386):     Mach-O dynamically linked shared library i386
    Myapp.app/Contents/Frameworks/Growl.framework/Growl:                                                        Mach-O universal binary with 2 architectures
    Myapp.app/Contents/Frameworks/Growl.framework/Growl (for architecture x86_64):	                            Mach-O 64-bit dynamically linked shared library x86_64
    Myapp.app/Contents/Frameworks/Growl.framework/Growl (for architecture i386):	                            Mach-O dynamically linked shared library i386
    Myapp.app/Contents/Frameworks/Growl.framework/Versions/A/Growl:                                             Mach-O universal binary with 2 architectures
    Myapp.app/Contents/Frameworks/Growl.framework/Versions/A/Growl (for architecture x86_64):	            Mach-O 64-bit dynamically linked shared library x86_64
    Myapp.app/Contents/Frameworks/Growl.framework/Versions/A/Growl (for architecture i386):	                    Mach-O dynamically linked shared library i386
    Myapp.app/Contents/MacOS/Myapp:                                                                             Mach-O 64-bit executable x86_64

    I have colored the important ones in green. They are the bundles of interest. The others are just aliases. Certain universal (32 bit and 64 bit) bundles are shown twice but you will see only one bundle in the location pointed to. My application had only frameworks and the main executable but in your case there could be other bundles as well.

  3. Verify the Entitlements of all the bundles of interest.
    //This bundle has Entitlements
    $ codesign -d --entitlements - /Users/Sayeed/Desktop/Myapp.app/
    
    Executable=/Users/Sayeed/Desktop/Myapp.app/Contents/MacOS/Myapp
    ??qq?<?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
    	<key>com.apple.application-identifier</key>
    	<string>83YFQ426C5.com.app.*>/string>
    	<key>com.apple.security.app-sandbox</key>
    	<true/>
    	<key>com.apple.security.files.user-selected.read-write</key>
    	<true/>
    	<key>com.apple.security.network.client</key>
    	<true/>
    	<key>com.apple.security.print</key>
    	<true/>
    </dict>
    </plist>
    
    //This bundle doesn't have entitlements
    $ codesign -d --entitlements - /Users/Sayeed/Desktop/Myapp.app/Contents/Frameworks/CrashReporter.framework/Versions/A/CrashReporter
    
    Executable=/Users/Sayeed/Desktop/Myapp.app/Contents/Frameworks/CrashReporter.framework/Versions/A/CrashReporter
    
  4. Verify the Code signatures and Designated Requirements (DR) of all the bundles of interest.
    $ codesign --verify --verbose=4 /Users/Sayeed/Desktop/Myapp.app
    
    /Users/Sayeed/Desktop/Myapp.app: valid on disk
    /Users/Sayeed/Desktop/Myapp.app: satisfies its Designated Requirement
    
    $ codesign --verify --verbose=4 /Users/Sayeed/Desktop/Myapp.app/Contents/Frameworks/CorePlot.framework/Versions/A/Coreplot
    
    /Users/Sayeed/Desktop/Myapp.app/Contents/Frameworks/CorePlot.framework/Versions/A/Coreplot: valid on disk
    /Users/Sayeed/Desktop/Myapp.app/Contents/Frameworks/CorePlot.framework/Versions/A/Coreplot: satisfies its Designated Requirement
    Important: Xcode on Mac OS X Maverics doesn’t allow you to sign a bundle if any nested bundle in it is unsigned. These nested bundles could be things like helper executables, libraries, embedded frameworks, plug-ins, XPC services. Therefore

    1. You should sign the unsigned bundles with your own code signing identity i.e. your Developer Id Certificate or App Store Distribution Certificate.
    2. It is recommended that you re-sign the bundles that are already signed by third parties with your own code signing identity i.e. your Developer Id Certificate or App Store Distribution Certificate.

    Here is how you should do it.

  5. Verify the Identifiers, Signer Details and Trust Chain, Designated Requirements (DR) of all the bundles of interest.
    $ codesign --display --requirements - --verbose=4 Myapp.app/
    
    Executable=/Users/Sayeed/Desktop/Myapp.app/Contents/MacOS/Myapp
    Identifier=com.app.myapp
    Format=bundle with Mach-O thin (x86_64)
    CodeDirectory v=20200 size=3804 flags=0x0(none) hashes=181+5 location=embedded
    Hash type=sha1 size=20
    CDHash=4145a92202f852303290579c641dab3c36336b1f
    Signature size=4353
    Authority=3rd Party Mac Developer Application: Sayeed Hussain (83YFQ426C5)
    Authority=Apple Worldwide Developer Relations Certification Authority
    Authority=Apple Root CA
    Signed Time=13-Jun-2014 12:10:11 am
    Info.plist entries=35
    TeamIdentifier=83YFQ426C5
    Sealed Resources version=2 rules=12 files=49
    designated => identifier "com.app.myapp" and anchor apple generic and certificate leaf[subject.CN] = "3rd Party Mac Developer Application: Sayeed Hussain (83YFQ426C5)" and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */
    
    $ codesign --display --requirements - --verbose=4 Myapp.app/Contents/Frameworks/CrashReporter.framework/Versions/A/CrashReporter
    
    Executable=/Users/Sayeed/Desktop/Myapp.app/Contents/Frameworks/CrashReporter.framework/Versions/A/CrashReporter
    Identifier=coop.plausible.CrashReporter
    Format=bundle with Mach-O universal (i386 x86_64)
    CodeDirectory v=20200 size=1532 flags=0x0(none) hashes=69+3 location=embedded
    Hash type=sha1 size=20
    CDHash=3195a79f058becf75f663cd1fea96d9f75c7ba4b
    Signature size=4353
    Authority=3rd Party Mac Developer Application: Sayeed Hussain (83YFQ426C5)
    Authority=Apple Worldwide Developer Relations Certification Authority
    Authority=Apple Root CA
    Signed Time=13-Jun-2014 12:10:10 am
    Info.plist entries=16
    TeamIdentifier=83YFQ426C5
    Sealed Resources version=2 rules=12 files=22
    designated => identifier "coop.plausible.CrashReporter" and anchor apple generic and certificate leaf[subject.CN] = "3rd Party Mac Developer Application: Sayeed Hussain (83YFQ426C5)" and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */
  6. If you are building for Mac App Store skip this step. If you are distributing outside of the Mac App Store, this is the last step. Verify that Gatekeeper will accept your app.
    $ spctl --verbose=4 --assess --type execute /Users/Sayeed/Myapp.app
    
    /Users/Sayeed/Myapp.app: accepted
    source=Developer ID
    

    and you are done.

  7. If you are distributing via the Mac App Store, follow this and the next step. You need to first create an xcarchive by choosing Product > Archive in Xcode. Then, using Terminal, you need to export it as a .pkg file as shown.
    $ xcodebuild -exportArchive -exportFormat PKG -archivePath  /Users/Sayeed/Desktop/Myapp\ 13-06-14\ 12.10\ am.xcarchive -exportPath /Users/Sayeed/Desktop/Myapp -exportSigningIdentity "3rd Party Mac Developer Application: Sayeed Hussain (83YFQ426C5)" -exportInstallerIdentity "3rd Party Mac Developer Installer: Sayeed Hussain (83YFQ426C5)"
    productbuild: Adding component at /var/folders/g3/spw0ywfj4d3_rz8jbkxz4lt80000gn/T/28EB1C81-63CD-444C-96BE-9BF8DA01A34E-4171-000001432522843D/Myapp.app
    productbuild: Signing product with identity "3rd Party Mac Developer Installer: Sayeed Hussain (83YFQ426C5)" from keychain /Users/Sayeed/Library/Keychains/login.keychain
    productbuild: Adding certificate "Apple Worldwide Developer Relations Certification Authority"
    productbuild: Adding certificate "Apple Root CA"
    productbuild: Wrote product to /var/folders/g3/spw0ywfj4d3_rz8jbkxz4lt80000gn/T/28EB1C81-63CD-444C-96BE-9BF8DA01A34E-4171-000001432522843D/Myapp.pkg
    productbuild: Supported OS versions: [10.7, )
    Moving exported product to '/Users/Sayeed/Desktop/Myapp.pkg'
    ** EXPORT SUCCEEDED **
    
    

    Myapp.pkg file will get generated.

  8. Verify the Myapp.pkg file by running the installer with -store option.
    $ sudo installer -store -pkg /Users/Sayeed/Desktop/Myapp.pkg
    
    installer: Note: running installer as an admin user (instead of root) gives better Mac App Store fidelity
    installer: Myapp.pkg has valid signature for submission: 3rd Party Mac Developer Application: Sayeed Hussain (83YFQ426C5)
    installer: Installation Check: Passed
    installer: Volume Check: Passed
    installer: Bundle com.app.myapp will be installed to /Applications/Myapp.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
    

    and you are done.

Hope this comes handy to anyone submitting their app to the Mac App Store. That’s it for now. Good Luck And Good Life!!!

Mac App: Code Signing Frameworks

Until the introduction of Gatekeeper in Mac OS X 10.8, the concept of code signing (introduced in Mac OS X 10.5) was not so well discussed in the Mac developer community. Gatekeeper is a security feature introduced by Apple to ensure that Mac apps coming only from either App Store or from Registered Apple Developers (via their websites) are allowed to run on a User’s Mac by default. Users have the option of changing Gatekeeper settings at their own risk to allow apps from any source to run but most users don’t exercise that option.

Gatekeeper requires apps to be properly code signed. An app is considered properly code signed if the main executable and all the nested bundles (embedded frameworks, libraries, helper executables, plug-ins etc) contained in it are properly code signed.

Important: Xcode on Mac OS X Maverics doesn’t allow you to sign a bundle if any nested bundle in it is unsigned. These nested bundles could be things like helper executables, libraries, embedded frameworks, plug-ins, XPC services. Therefore

  1. You should sign the unsigned bundles with your own code signing identity i.e. your Developer Id Certificate or App Store Distribution Certificate.
  2. It is recommended that you re-sign the bundles that are already signed by third parties with your own code signing identity i.e. your Developer Id Certificate or App Store Distribution Certificate.

Code Signing Bundles The Wrong Way

Some googling would lead you to a “quick” fix on the internet to recursively sign all the nested bundles in your app. The “quick” fix is to use codesign’s –deep option in “Other Code Signing Flags” in your target’s build settings. But this solution is incorrect due to the fact that while recursively signing the nested bundles, –deep applies top-level bundle parameters like your app’s Entitlements to all the nested bundles rendering them invalid.

When users download and install such an app, Gatekeeper will notify them that it is damaged and cannot be opened. If you check the app using command line, here is what you get

$ spctl --verbose=4 --assess --type execute /Users/Sayeed/Myapp.app
/Users/Sayeed/Myapp.app: a sealed resource is missing or invalid

Code Signing Bundles The Right Way

The right way to code sign nested bundles is to add another Build Phase to your target.

When you embed frameworks, you add a “Copy Files” build phase to copy them into the Frameworks folder in your app bundle. This enables the app to run on the users’ systems because these frameworks don’t ship by default on Mac OS X. To code sign embedded frameworks after they are copied, add a Run Script Build Phase from Xcode > Editor > Add Build Phase. The Shell is bash (/bin/sh) and the script looks like

LOCATION="${BUILT_PRODUCTS_DIR}"/"${FRAMEWORKS_FOLDER_PATH}"
IDENTITY="3rd Party Mac Developer Application: Sayeed Hussain (83YFQ426C5)"
codesign --verbose --force --sign "$IDENTITY" "$LOCATION/Coreplot.framework/Versions/A"
codesign --verbose --force --sign "$IDENTITY" "$LOCATION/CrashReporter.framework/Versions/A"
#other embedded frameworks
Important: Frameworks are “versioned bundles”, and each contained version should be signed and validated separately. For example:
$ codesign -s my-signing-identity ../MyCustomFramework/Versions/A
$ codesign -s my-signing-identity ../MyCustomFramework/Versions/B
All embedded frameworks need to be signed separetly by adding the codesign command in the shell script.

If you are bulding to distribute outside of the Mac App Store, you should use your “Developer ID Application” code signing identity. If you are building for the Mac App Store, you should use your “3rd Party Mac Developer Application” code signing identity. Other embedded bundles like helper executables, plug-ins or XPC services, need to be signed appropriately after being copied into the app bundle.

Go ahead and code sign your embedded frameworks the right way. That’s it for now. Good Luck And Good Life!!!

I got an App Store Rejection

I am an iOS developer by profession. Recently, I decided to pursue an idea of my own and at the same time diversify my skill set. Ergo, I decided to build my first Mac App. So I quit my job and started working on my idea. After a few months of hard work on the Mac App and the website and a few hiccups, I was ready to submit the app to app store. Praying to god for good luck but also slightly dreading the worse, I pressed the Upload button. Three days later, lo and behold! I was staring at a REJECTI@N from Apple for these reasons:

    2.1: Apps that crash will be rejected
    2.21: Apps may not use update mechanisms outside of the App Store
    2.5: Apps that use non-public APIs will be rejected

Bad news I said to myself. But not only was I determined to push the app through, I already had the roadmap for the next version ready. There was no way I was going to let this setback slow me down even for a moment. I sat down and rectified the errors as follows:

2.1: Apps that crash will be rejected

There were two crashes noticed by Apple and they had attached the crash reports for debugging.

  1. Looking at the logs, Crash1 happened due to NSPortTimeoutException when NSSpellChecker class is used by the app for the first time after system start. I was using it to give users auto-suggestions as they start typing in a textfield. In my code, I was doing my own exception handling using the ExceptionHandling.framework. I changed my
    - (BOOL)exceptionHandler:(NSExceptionHandler *)sender shouldHandleException:(NSException *)exception mask:(NSUInteger)aMask{
            
    }
    

    method’s implemetation. That fixed it.

  2. Crash2 was related to MASRecieptValidation workflow. The app checked for the presence of a valid MacAppStore receipt stored in ExpenseTrack.app/Contents/_MASReceipt. When an app is downloaded from the Mac App Store, this receipt is installed by default and receipt validation succeeds. But while Apple was reviewing it, this receipt was absent and the app exited with exit code 173. During my testing, I created a test account on iTunesConnect to generate a dummy receipt. I said Apple that if they wanted to test the dummy receipt generation/validation workflow, they can followed these steps:
    1. Kill storeagent using killall -KILL storeagent (without this, the sign in prompt was not showing. Please refer to http://furbo.org/2013/10/21/mac-app-store-receipts-and-mavericks/ for more details).
    2. Delete, install and launch the app.
    3. The app runs its receipt validation code which fails because the receipt is absent (this won’t happen when the app is installed from Mac App Store because the receipt will be installed by default).
    4. The app quits with exit code 173 signalling storeagent to get a valid receipt.
    5. Storeagent prompts users to sign in with Apple Id and fetches and installs the receipt in the ExpenseTrack.app/Contents/_MASReceipt folder and then relaunches the app.
    6. The receipt validation code succeeds because the receipt is now present.

    That fixed it.

2.21: Apps may not use update mechanisms outside of the App Store

In the app, I had provided a Check For Updates menu option to allows users to check for updates. Apple thought that through this option I was providing an update mechanism outside of the App Store. I don’t blame them because on the face of it, it appeared so. But it wasn’t as it looked. Here is how it worked:

  1. I upload an new version to iTunesConnect and update my back-end(server) with that version number once it goes live.
  2. The app when launched makes an http request to our back-end to check for the latest available app store version.
  3. The app receives and compares it with its own version. If received version > app’s version, it generates a Growl/NSUserNotificationCenter notification which when clicked launches the App Store app on the Mac using macappstore://myappurl. This loads the app’s page in the App Store app allowing users to download the new version.

So you see, it wasn’t as it looked. But I removed the option without arguing my case any further with Apple.

2.5: Apps that use non-public APIs will be rejected

This is what Apple said, “The app includes OBJC_IVAR_$_NSView._frame from the framework ‘/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit'”. This was a little unexpected. I somehow ended up using NSView’s _frame iVar (private iVar) directly in a subclass of NSView in my code. I used otool and nm as suggested by Apple to identify the culprit class and changed the iVar usage.

After these changes I was ready to go again. I hit the Upload button once more after saying my prayers of course. Three days later, lo and behold! the app was Ready For Sale. June 16th 2014, 10:56 AM was a happy moment for me. My first Mac app had been released. All the perseverance had paid off. I thanked god, heaved a big sigh, pat myself on the back and started work on the next version. I wish everyone Good Luck And Good Life!!!

iTunes Link Maker

You have burnt the midnight oil over the last few months and finally submitted your app to the Mac App Store. Apple has approved it. Now comes the time to embed your app’s App Store link into your product website. Enter iTunes Link Maker.

On iTunes Link Maker, search for your app by providing the right parameters. Your app should appear in the search results. Click on the “Mac App Link” and you can get the direct link to your app or a small/large embeddable html code for a button. The button assets are provided by Apple servers. Cool right!! Go ahead and use it on your product website.

I wanted the behavior on link click to open the app page on iTunes in the browser and also open the App Store app on Mac with the app details. The iTunes Link Maker link I got for my app

https://itunes.apple.com/in/app/expensetrack/id870188888?mt=12&uo=4

was just opening the app page in the browser but didn’t open the App Store app on Mac so I had to change it to

https://itunes.apple.com/in/app/expensetrack/id870188888?mt=12&ls=1

to get the desired behavior.

If you wish to add your app’s link in the app bundle before submitting to App Store for say “Rate Us” or “Write A Review” implementation etc., you can use the following code snippet in your app

[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:macappstore://itunes.apple.com/app/id870188888?mt=12]];

This code opens the app page in the App Store app. An app gets assigned an id (870188888) the moment you create it in the iTunesConnect portal.

Provisioning Profiles And Mac App Distribution

When faced with distributing Mac OS X apps, you would deal with the following possible use cases:

  1. Distributing a development app to beta users for testing
    For this you have two choices:

    1. Don’t code sign the app and ask your beta users to allow Gatekeeper(available 10.7.5 onwards) to install apps from anywhere. Gatekeeper setting is available in Apple Menu > System Preferences > Security & Privacy > General. You won’t need any certificates or provisioning profiles if you take this path.
    2. Codesign the app with a developer certificate and a development provisioning profile that contains the mac device identifier(hardware uuid) of the beta users’ macs(like in the iOS world). This uuid can be obtained from Apple Menu > About This Mac > More Info > System Report > Hardware Overview > Hardware UUID. Relevant Gatekeeper setting needs to be applied to run apps signed this way.
  2. Distributing a production app outside of Mac App Store (say via a website)
    For this no provisioning profile is required. Only these two certificates are needed – Developer Id Application Certificate, Developer Id Installer Certificate. Gatekeeper setting should be “Allows apps from: Mac App Store and identified developers”. This is the default Gatekeeper setting. However if you have changed this setting to “Allow apps from: Mac App Store”, apps signed this way won’t run on your Mac.
  3. Distributing a production app via the Mac App Store
    For this you need a distribution provisioning profile and these two certificates – 3rd Party Mac Developer Application Certificate, 3rd Party Mac Developer Installer Certificate. Mac App Store apps are not blocked by Gatekeeper.


    Note: Distribution provisioning profiles don’t let you add devices as one would expect. They are only used for pushing apps to Mac App Store.