20

My company uses one build machine (a Mac Mini) as a CI node to build our iOS app. We currently build an Ad-Hoc and an App Store config on the mini. We've recently enrolled in the Enterprise Program and want to start building an Enterprise config as well. However, our build process now fails, because we now have two certificates called "iPhone Distribution: Widget Corporation". One is the distribution cert for AdHoc/AppStore, and one is for Enterprise (Apple calls it In-House).

I've tried modifying the mini's keychains such that one cert is in the login keychain and one is in a new keychain called "enterprise", but this just shifted the error from the start of the build:

CodeSign error: Certificate identity 'iPhone Distribution: Widget Corporation' appears more than once in the keychain.

to the end of the build:

iPhone Distribution: Widget Corporation: ambiguous (matches "iPhone Distribution: Widget Corporation" in /Users/hudson.admin/Library/Keychains/login.keychain and "iPhone Distribution: Widget Corporation" in /Users/hudson.admin/Library/Keychains/enterprise.keychain)

My question is whether or not there's a way to properly sandbox the two certificates so I can build Ad-Hoc, App Store, and In-House versions of the app on the same machine. The only possible solution I've yet to try is to actually bundle the certs along with the source and use security to add and delete the certificates as I need them; clearly that solution isn't very pretty and poses security risks.

Any ideas?

kevboh
  • 5,207
  • 5
  • 38
  • 54
  • I've submitted this question to Apple as a TSI. I'll update with their answer if I get one. – kevboh Mar 04 '11 at 15:20

5 Answers5

17

After discussing with Apple Developer Technical Support, they've advised creating separate keychains to house the different certificates and then pass the --keychain filename argument into the codesign step to point at the appropriate file. You can pass this argument into Xcode or xcodebuild using the OTHER_CODE_SIGN_FLAGS option. eg:

xcodebuild -target "<targetname>" -configuration "<configname>" \
  PROVISIONING_PROFILE=A3A47A82-E91F-4E95-8559-601C6C857053 \
  OTHER_CODE_SIGN_FLAGS="--keychain=/Users/username/Library/Keychains/enterprise.keychain" \
  build  

Also, after creating a new keychain it seems to default to relocking after 5 minutes - you might want to change this if you have builds that take a while.

JosephH
  • 37,173
  • 19
  • 130
  • 154
kevboh
  • 5,207
  • 5
  • 38
  • 54
  • 1
    Thanks kevboh, this worked well for me! I've added an example command line into your answer in case it's useful to others. I actually put the keychain file into my RCS now, so can use it directly from the source tree. – JosephH Jul 27 '11 at 21:25
  • 1
    FYI, this can be configured in Xcode 4 under Project navigator > _project_ > _target_ > Build Settings > Code Signing section > Other Code Signing Flags. Enter the entire value, such as: `--keychain=/Users/username/Library/Keychains/enterprise.keychain` – phatblat Oct 01 '11 at 05:55
  • I'm really struggling to get this method to work with xcode 4.3.2 (it was working fine with 4.2) - codesign fails with "no identity found" – JosephH Mar 23 '12 at 13:12
  • @kevboh I've been able to get it to work with xcode 4.3.2 by doing: `security list-keychain -s ./enterprise.keychain` before doing the build - it's not exactly ideal though! – JosephH Mar 26 '12 at 17:11
  • This is still working for me using the Xcode UI and setting `--keychain` in the Other Code Signing Flags setting, I'm not using it with xcodebuild so ymmv there. I just set it in the configuration, then pass the configuration to xcodebuild. – kevboh Feb 28 '13 at 21:55
  • I am wondering how this is all possible when you cannot create the same App ID in two different accounts. Doesn't the enterprise certificate have to contain the same App ID to build the app? – CMVR Nov 04 '13 at 20:52
9

Another way which helped me is to give the signing identity as a SHA1 hash to codesign. Steps:

  1. Find the SHA1 hash in keychain access of the needed certificate
  2. Compare the SHA1 hash with the one returned by: security find-identity -v -p codesigning
  3. Use the right SHA1 from step 2 for codesign: codesign -s "SHA1_FROM_STEP2" ...
homer_simpson
  • 193
  • 2
  • 6
  • 3
    Just to confirm, I tried and using the hashcode in xcrun works, and prevent any ambiguous naming collision ! – XGouchet Mar 20 '13 at 11:24
  • 1
    To clarify @XGouchet's response, you can use the SHA1 fingerprint of the certificate as the value of the --sign parameter in xcrun as follows: `xcrun -sdk iphoneos PackageApplication -sign <40 character SHA1 fingerprint here>...`. In my case, this allowed me to use both my developer and enterprise certificates without any ambiguity, calling Apple, renaming, or creating a new keychain – Drew H Aug 17 '13 at 20:16
5

After speaking with the xcode team at WWDC, they suggested a much simpler solution - that I could request that my enterprise certificate is renamed so there isn't a clash.

To do this, contact Developer Services by clicking the "Managing Your Account" link on the developer contact page then selecting "iOS Provisioning Portal" as the subject - they did this for me within a day of me asking.

This is far, far simpler than any other way - I now have both sets of certificates in my keychain, and can happily build for appstore or enterprise distribution without doing anything more than selecting the right entity to codesign with.

JosephH
  • 37,173
  • 19
  • 130
  • 154
  • Oh heavens, this would be amazing. I just requested them to do the same for our enterprise account. – phatblat Jul 25 '12 at 04:29
  • I made this request as well, but was told it was a no-go. I haven't been able to get above solution to work either (though I didn't sink a ton of time into it), and have been deleting the certificate that I'm not using when doing builds. It isn't the greatest. – Robert Zahm Nov 16 '12 at 19:12
  • Yes, I tried to make this request for another customer, and also got stone walled. It's not clear why it worked so easily the first time I tried... – JosephH Dec 15 '12 at 08:12
  • It took 3 months to get Apple to change the organization name on our iOS Developer Enterprise Program, but it's totally worth it. I had worked around this issue by setting up separate keychains and jenkins nodes (each using separate OS X users). After generating new certs which picked up the new org name, I can finally say that the node/user/keychain partitioning is no longer necessary. Additionally, the OTHER_CODE_SIGN_FLAGS="--keychain=..." solution provided by @kevboh does not work in all cases. If memory serves, that setting isn't picked up by the Xcode Organizer archive/resign action. – phatblat Sep 06 '13 at 06:34
0

I've had a lot of trouble with this. Probably the best solution is to just request Apple that your certificate is renamed, but if you don't want to deal with that I used a different solution. I have a folder where I exported both the regular and the enterprise certificates. Then you can delete the certificate you are not using and import the other one. Maybe this is more hassle, but usually I only distribute apps in enterprise, so it's not that much trouble.

By the way, what I do to delete a certificate is select the certificates filter, which then shows the associated private key, and then I delete both the certificate and the key. If I delete only the certificate Xcode keeps creating it again.

José Manuel Sánchez
  • 5,215
  • 2
  • 31
  • 24
0

To elaborate on homer_simpson's answer: it's possible to compute SHA1 of your .p12 file directly (without using security calls), and then feed the result to codesign or xcrun. Here's an excerpt from my autobuild script:

# get SHA1 of .p12 file and pass it to PackageApplication to prevent ambiguity in cert selection
# sample output of openssl: SHA1 Fingerprint=14:B0:58:D1:F9:1D:A5:74:0A:AA:BE:B9:F2:7A:7E:AD:58:82:A2:25
# fingerprint (everything after =) is extracted with cut, and : are removed with sed

# ${IDENTITY} is a variable that contains path to your .p12 file. passphrase is empty in this case.
P12_SHA=$(openssl pkcs12 -in "${IDENTITY}" -nodes -passin pass: | openssl x509 -noout -fingerprint -sha1 | cut -d = -f 2 | sed -e 's/://g')

/usr/bin/xcrun -sdk iphoneos PackageApplication -s "${P12_SHA}" ...
kambala
  • 2,341
  • 19
  • 20