40

Below is my build script (not using xcodebuild plugin).

  1. Build step works
  2. I have created a separate keychain with the required certs and private keys, and they are visible in Keychain Access
  3. keychain commands don't fail in the script
  4. security list-keychains shows these as valid keychains

It's acting like unlock command doesn't truly succeed. When I try to run codesign from the command line via

codesign -f -s "iPhone Developer: mycert" -v sample.app/ --keychain /Users/Shared/Jenkins/Library/Keychains/JenkinsCI.keychain

I get

CSSM_SignData returned: 000186AD
sample.app/: unknown error -2070=fffffffffffff7ea

although I'm not sure I'm emulating from the command line properly since you can at best

sudo -u jenkins bash

xcodebuild ONLY_ACTIVE_ARCH="NO" CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED="NO" -scheme "MySchemeName" CONFIGURATION_BUILD_DIR="`pwd`"
security list-keychains -s /Users/Shared/Jenkins/Library/Keychains/JenkinsCI.keychain
+ security default-keychain -d user -s /Users/Shared/Jenkins/Library/Keychains/JenkinsCI.keychain
+ security unlock-keychain -p jenkins /Users/Shared/Jenkins/Library/Keychains/JenkinsCI.keychain
+ security list-keychains
    "/Users/Shared/Jenkins/Library/Keychains/JenkinsCI.keychain"
    "/Library/Keychains/System.keychain"
+ security default-keychain
    "/Users/Shared/Jenkins/Library/Keychains/JenkinsCI.keychain"
+ codesign -f -s '$IDENTITY_GOES_HERE.' -v sample.app/
sample.app/: User interaction is not allowed.

Any help is greatly appreciated.

gudatcomputers
  • 2,822
  • 2
  • 20
  • 27

12 Answers12

80

We don't use Jenkins but I've seen this in our build automation before. Here's how we solved it:

1) Create your build Keychain. This will contain the private key/certificate used for codesigning:

security create-keychain -p [keychain_password] MyKeychain.keychain

The keychain_password is up to you. You'll use this later to unlock the keychain during the build.

2) Import the private key (*.p12) for your CodeSign identity:

security import MyPrivateKey.p12 -t agg -k MyKeychain.keychain -P [p12_Password] -A

The key here is the "-A" flag. This will allow access to the keychain without warning. This is why you're seeing the "User interaction is not allowed" error. If you were attempting this build via the Xcode UI, this is the point where it would prompt you to "Allow access" to your keychain.

3) However you're saving the Keychain (e.g.: checking it in to source control), make sure it's writeable and executable by your build user.

When you're ready to build, add the following prior to running xcodebuild:

# Switch keychain
security list-keychains -s "/path/to/MyKeyhain.keychain"
security default-keychain -s "/path/to/MyKeychain.keychain"
security unlock-keychain -p "[keychain_password]" "/path/to/MyKeychain.keychain"

If you're running locally, you may want to add something at the end of your build script that switches back to the login keychain (~/Library/Keychains/login.keychain), e.g.:

# Switch back to login keychain
security list-keychains -s "~/Library/Keychains/login.keychain"
security default-keychain -s "~/Library/Keychains/login.keychain"

Give that a try. We create a separate Keychain for each identity we use (our own plus builds on behalf of customers). In our company's case, we have both an AppStore and Enterprise account. This can result in naming conflicts while codesigning (e.g.: both accounts resolve to "iPhone Distribution: ACME Corporation"). By keeping these identities in separate keychains we avoid this conflict.

Jamieson
  • 991
  • 1
  • 7
  • 4
  • wow.. necro post on this one.. but very cool... I understand exactly what you mean about the -A flag. I'll give it a shot when we setup CI for our new app. Thanks :) – gudatcomputers Oct 27 '13 at 03:03
  • I was struggling with this and this is exactly what I needed. Thank you Jamieson. – KyleT Mar 20 '14 at 21:12
  • can anyone help on this https://stackoverflow.com/questions/52187300/build-issue-using-fastlane-failed-on-jenkins?noredirect=1#comment91352951_52187300 – Sanoj Kashyap Sep 18 '18 at 12:20
  • This fix is still relevant on macOS Mojave (10.14.5). Thanks @jamieson – dvilla Feb 04 '20 at 23:23
  • Make sure to use full paths for the parameters to `security` when referencing the keychain file. I was using a relative path and it was not unlocking the keychain. – chrish Feb 21 '20 at 14:25
  • 2
    KUDOS do @Jamieson for this answer in 2017. It seems the problem got resolved in that time. However, I would adivice to update this answer and mention "Stephen Quan" solution as the most up to date version. This answer here seems to not work anymore. Stephen Quan is the right one now! Upvoting both! :-) – Wagner Patriota Mar 23 '20 at 04:28
28

Moving the certs to the System keychain, and referencing it specifically fixed the issue

gudatcomputers
  • 2,822
  • 2
  • 20
  • 27
  • 5
    Even after I had copied the signing certificate to the System keychain, the build still failed with the same error until I actively removed the 'original' from the login keychain – Marmoy Apr 27 '15 at 07:31
  • Worked for me, and easiest solution. – Quanlong May 22 '15 at 07:51
  • Using Jenkins 2.235.3 LTS with a Mac agent (connecting via SSH) and Xcode 11.6, this is the solution that worked for me (moving, not copying, the certs from the Login to the System keychain). – Ken Jul 31 '20 at 19:31
  • also this walkthrough of codesign from logged in in ui, then via ssh, helped diagnose the issue quickly: https://developer.apple.com/forums/thread/712005 – Markus Hütter Feb 21 '23 at 15:42
18

In this answer, we add / remove your iOS certificate without manipulating the login keychain nor changing the default keychain by:

  1. Use a temporary keychain
  2. Append temporary keychain to the search list (not replacing)
  3. Unlock temporary keychain with no timeout
  4. Import your certificate using -T /usr/bin/codesign
  5. Do the build
  6. Delete certificate by deleting temporary keychain

Create a temporary keychain. I add $$ which is the PID to create a unique name for the keychain. This allows multiple temporary keychains to be created without clashing. This is useful, if we running concurrent Jenkins jobs.

# Create temporary keychain
MY_KEYCHAIN="MyKeychain-$$.keychain"
MY_KEYCHAIN_PASSWORD="secret"
security create-keychain -p "$MY_KEYCHAIN_PASSWORD" "$MY_KEYCHAIN"

Appends temporary keychain to the search list. Be careful to use security list-keychains -s to append your keychain, else, you will clobber builds running in another thread:

# Append keychain to the search list
security list-keychains -d user -s "$MY_KEYCHAIN" $(security list-keychains -d user | sed s/\"//g)
security list-keychains

Unlocks temporary keychain with no automatic relocking timeout (security set-keychain-settings). If you forget to fix the relocking timeout, builds taking longer than the default relocking timeout (typically about 30 minutes) will trigger the password prompt:

# Unlock the keychain
security set-keychain-settings "$MY_KEYCHAIN"
security unlock-keychain -p "$MY_KEYCHAIN_PASSWORD" "$MY_KEYCHAIN"

Import iOS certificate and grants /usr/bin/codesign access without requiring a password prompt.

# Import certificate
security import $CERT -k "$MY_KEYCHAIN" -P "$CERT_PASSWORD" -T "/usr/bin/codesign"

Since the temporary keychain contains only 1 certificate we can, programmatically, derive the IOS_IDENTITY (typically required as an input to build steps).

# Detect the iOS identity
IOS_IDENTITY=$(security find-identity -v -p codesigning "$MY_KEYCHAIN" | head -1 | grep '"' | sed -e 's/[^"]*"//' -e 's/".*//')
IOS_UUID=$(security find-identity -v -p codesigning "$MY_KEYCHAIN" | head -1 | grep '"' | awk '{print $2}')

The security set-key-partition-list is a new/additional requirement for unlocking the certificate.

# New requirement for MacOS 10.12
security set-key-partition-list -S apple-tool:,apple: -s -k $MY_KEYCHAIN_PASSWORD $MY_KEYCHAIN

Do your build now:

# Insert your custom build steps

Delete temporary keychain. Because the build is done, we no longer require the keychain and the certificate. Deleting the temporary keychain will automatically pop it from the search list. i.e. all other keychains will remain.

# Delete the temp keychain
security list-keychains
security delete-keychain "$MY_KEYCHAIN"
security list-keychains
Stephen Quan
  • 21,481
  • 4
  • 88
  • 75
  • This still isn't working on jenkins for me. It works when I use it locally, it works when running on the build machine via SSH. It fails when running on the build machine via jenkins. – Max Oct 13 '21 at 23:12
  • I think my issue is due to an [Apple cert change](https://developer.apple.com/support/expiration/). – Max Oct 14 '21 at 15:59
  • Yep, just needed to add the [new cert](https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer) to my system keychain – Max Oct 15 '21 at 15:42
16

Required to unlock keychain before to sign "security unlock-keychain -p"

user2317738
  • 281
  • 2
  • 10
  • as I stated in my answer below, adding it to system worked. If you reference the script pasted above I did have "security unlock-keychain -p" and it was successfully doing so... it just wouldn't respect it until it was on System. There may have been a solution that didn't involve using System... but for a Continuous Integration server I think that's an acceptable solution. – gudatcomputers Jun 21 '13 at 17:14
  • I encounter this problem again, and this time `unlock` solves my problem. – AechoLiu May 25 '16 at 03:02
  • definitely THE solution. – Luca Davanzo Jun 29 '16 at 10:56
  • when I ssh into the box to make a build, this was the solution. – Ken Town Oct 04 '19 at 18:08
10

Only one thing solved this problem for me.

What I did is setting the Private Key of the Signing Certificate in the Keychain Access to Allow all applications to access this item.

enter image description here

raed
  • 4,887
  • 4
  • 30
  • 49
5

FWIW... let me throw out another possible reason for this. You may have duplicate certificates floating around and codesign can't tell which one to use. When you run this command from your Jenkins slave do you see duplicate, valid certificates? Something like this:

$ security find-identity -v -p codesigning
  1) AAAAE00066DED2FE77DF43012573AD5B6188AAAA "iPhone Developer: JOHN SMITH (XAAAAFSUSJ)"
  2) AAAAE00066DED2FE77DF43012573AD5B6188AAAA "iPhone Developer: JOHN SMITH (XAAAAFSUSJ)"
  3) BBBB5B03DB566209964247982908D3DD74D1BBBB "iPhone Distribution: Example, Inc. (TBBBBH5HUE)"
  4) BBBB5B03DB566209964247982908D3DD74D1BBBB "iPhone Distribution: Example, Inc. (TBBBBH5HUE)"
  5) BBBB5B03DB566209964247982908D3DD74D1BBBB "iPhone Distribution: Example, Inc. (TBBBBH5HUE)"
  6) AAAAE00066DED2FE77DF43012573AD5B6188AAAA "iPhone Developer: JOHN SMITH (XAAAAFSUSJ)"
  7) AAAAE00066DED2FE77DF43012573AD5B6188AAAA "iPhone Developer: JOHN SMITH (XAAAAFSUSJ)"
  8) BBBB5B03DB566209964247982908D3DD74D1BBBB "iPhone Distribution: Example, Inc. (TBBBBH5HUE)"
  8 valid identities found

If so, I have found it useful to do the following and get back to a baseline set of signing certificates:

  • Delete all the certificates on the Jenkins slave (and other Jenkins slaves that will be running your build script).
  • Next: verify, you have 0 identifies by running $ security find-identity -v -p codesigning again.
  • Within your application's repository include a custom MyApp.keychain with the two valid certificates in it. Be sure to remove any duplicates.
  • Now, from your build script and before the codesign process runs from unlock MyApp.keychain and set it as the default. This exposes those certificates as available for codesign.
  • Finally, verify on your Jenkins slave again: $ security find-identity -v -p codesigning that you see only the certificates you bundled into MyApp.keychain and that there are no other signing identities on the system. If you still see duplicates after having done this you have other places where your Jenkins slave is being made aware of these certificates.
Aaron
  • 7,055
  • 2
  • 38
  • 53
3

I copied all the certs/private keys to a new keychain (you can right-click on the items and simply copy and paste). In the new keychain, right-click on each private key, Get Info -> Access Control and make the keys available to all apps.

Importantly, in the upper left of the Keychain app is the list of keychains. Re-order them so that the new keychain is first in the list.

Another answer I found gave the build step to unlock this keychain during the build:

KEYCHAIN=/Users/<you>/Library/Keychains/codesign.keychain

# the -s option adds $KEYCHAIN to the search scope, while the -d option adds $KEYCHAIN to the system domain; both are needed
security -v list-keychains -d system -s $KEYCHAIN
security -v unlock-keychain -p <keychain password> $KEYCHAIN
Graham Perks
  • 23,007
  • 8
  • 61
  • 83
  • so I did those same steps in the build process. I did NOT however do the granular keychain steps you mention earlier in your post. The issue for me was it runs AS Jenkins.. which I can't login as to re-order the keychain. – gudatcomputers Jul 25 '13 at 15:18
  • This was the answer I needed. Thank you. – hshepherd Jun 29 '17 at 17:34
2

Here what worked for me:

  1. I created a new keychain and copied all entries from "login" to it, named it "jenkins_ios"
  2. Made new keychain default.
  3. Added a new "Execute shell" step in Jenkins config, it should be the first step beforecode signing, containing the following:

KEYCHAIN=/Users/<user>/Library/Keychains/jenkins_ios.keychain
security -v list-keychains -s $KEYCHAIN
security -v unlock-keychain -p <password> $KEYCHAIN
security set-keychain-settings -t 3600 -l $KEYCHAIN

Last step is really important, as default unlock timeout may not be enough long for your project to build properly (exactly this happened with our project, as it is huge and build step took about 5-7 minutes, and keychain became locked at the moment it was required for codesign).

Mr Lister
  • 45,515
  • 15
  • 108
  • 150
CrazyJoeLv
  • 570
  • 3
  • 6
1

This might also be caused by a default timeout on the keychain.

Check out my answer to "User interaction is not allowed" trying to sign an OSX app using codesign

Community
  • 1
  • 1
yonix
  • 11,665
  • 7
  • 34
  • 52
  • in this case it was a short running build. I think in my case the problem originated because Jenkins wasn't a real user with a Desktop. In configurations since then we have been able to make the Jenkins user that can login, and have not needed to hack it into the System keychain. – gudatcomputers Jun 06 '14 at 04:49
1

That's a code signing error, the xcodebuild command can't access your certificate's private key since it's running through Jenkins' slave with SSH.

Run this line in your shell script before you run the xcodebuild in order to allow access:

security set-key-partition-list -S apple-tool:,apple: -s -k <ROOT-PASSWORD> /Users/<YOUR USER NAME>/Library/Keychains/login.keychain-db

Hope that helps!

Asaf Shveki
  • 736
  • 8
  • 11
1

If you face this issue on a CI (GitHub Actions in my case). Then don't forget to unlock the keychain where your certificates are installed before you run the xcodebuild command.

For example: security -v unlock-keychain -p <keychain password> $KEYCHAIN

If the keychain is locked the xcodebuild command will hang/freeze when trying to sign the app because it will be waiting for the keychain password to be entered and hence this is a CI and not your own machine there is no way to enter the password when you are asked for it.

You don't need to unlock the keychain if you build the app without code signing e.g ... CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY="" ...

Daniil
  • 141
  • 1
  • 11
0

I removed duplicate keys from the key chains (login and system) and it started working. I did only have one certificate but many keys so I had to filter on keys to see them properly.

magnusarinell
  • 1,127
  • 14
  • 22