Add a keychain to search list? - macos

I need to add a .keychain file to my keychains search list for some automated build tools. Currently I'm using security list-keychains command:
list-keychains [-h] [-d user|system|common|dynamic] [-s [keychain...]]
Display or manipulate the keychain search list.
This command let's you set the entire keychain search list, but it does not provide a way to simply add another keychain. So adding a keychain becomes a 2 step process.
Run list-keychains and parse the output
Then do something like list-keychains -s ${existing_chains} ${new_keychain}
While this works, it seems overly complicated and introduces a race condition.
Also it seems like open my.keychain will add it to the search list, but I tend to avoid using commands like open in scripting or headless environments.
Is there a simpler or better way to add a keychain to the search list?

A one line version of #mles solution above:
security list-keychains -d user -s $(security list-keychains -d user | sed -e s/\"//g) <new keychain>
The issue with directly piping in the output of security list-keychains -d user is it surrounds the results with quotes. Solution uses sed to strip them out.

It's 2017 and on macos 10.12.4 security create-keychain still does not add a new keychain to the search list. Here's my script to add and destroy temporary keychains step by step:
#!/bin/bash -e
uuid="$(uuidgen)"
echo "New Keychain name: $uuid"
keychains=$(security list-keychains -d user)
keychainNames=();
for keychain in $keychains
do
basename=$(basename "$keychain")
keychainName=${basename::${#basename}-4}
keychainNames+=("$keychainName")
done
echo "User keychains on this machine: ${keychainNames[#]}";
read -p "Enter to create keychain"
security -v create-keychain -p test123 $uuid
read -p "Enter to add keychain to searchlist"
security -v list-keychains -s "${keychainNames[#]}" $uuid
read -p "Enter to unlock keychain"
security -v unlock-keychain -p test123 $uuid
read -p "Enter to import certificate"
security -v import build-assets/certficate.p12 -k $uuid -P certificate_password
read -p "Enter to delete keychain"
security -v delete-keychain $uuid

Which automated tools are you using? I had a similar problem with building for iPhone using Jenkins under tomcat. I tried adding keychains in the shell script but it proved very flakey at best.
In the end, I worked around the problem by switching our build process to be running via LaunchAgents instead of LaunchDemons. This way the build tools run in the user context and things have become lot more reliable.
Is this a possibility for you? If so, I can provide more detail.

There is NOT a better way that I'm aware of - however it appears that maybe create-keychain will do what you want:
security create-keychain -h
returns:
Usage: create-keychain [-P] [-p password] [keychains...]
-p Use "password" as the password for the keychains being created
-P Prompt the user for a password using the SecurityAgent
Use of the -p option is insecure
Create keychains and add them to the search list.

Related

GitHub Actions: productsign hangs

I am having an issue with GitHub Actions. When I call productsign the job just hangs. When searching the internet it seems that the job tries to ask the user for a password but I do not get any errors or feedback from the logs. The job just hangs for ever. When run on my own computer everything works as expected and the .pkg is signed.
My step in the workflow is as follows
- name: Build & Sign Installer
run: |
export LC_ALL=en_US.UTF-8
export LANG=en_US.UTF-8
(cd fastlane && ./decrypt_secret.sh)
carthage update --use-xcframeworks --platform macOS
bundle exec fastlane set_release_version
bundle exec fastlane mac install_certificates
bundle exec fastlane mac build_main_app
bundle exec fastlane mac build_updater
bundle exec fastlane mac build_installer
(cd installer && productsign --sign <identity> app-1.0.0.pkg app-1.0.0-signed.pkg)
I have tried a lot of different solutions, but nothing works
security import ${P12_FILE} -k ${KEYCHAIN_PATH} -P ${P12_PASSWORD} -A
security import ${P12_FILE} -k ${KEYCHAIN_PATH} -P ${P12_PASSWORD} -T /usr/bin/productsign
Setting partition list using security set-key-partition-list
creating a new keychain / unlocking keychain
Switched to use the --sign param on productbuild (also hangs when --sign added)
Manually imported the certificate without fastlane match at all
I think any other solution found on google
Any ideas? Is this a bug in GitHub Actions?
Ok, we finally figured it out. The solution is to create tmp keychain, set its as default and configure some attributes. This makes sure codesign and productsign can access it without being prompted for a password.
Setup Tmp Keychain
# default again user login keychain
security list-keychains -d user -s login.keychain
# Create temp keychain
security create-keychain -p "$MY_KEYCHAIN_PASSWORD" "$MY_KEYCHAIN"
# Append temp keychain to the user domain
security list-keychains -d user -s "$MY_KEYCHAIN" $(security list-keychains -d user | sed s/\"//g)
# Remove relock timeout
security set-keychain-settings "$MY_KEYCHAIN"
# Unlock keychain
security unlock-keychain -p "$MY_KEYCHAIN_PASSWORD" "$MY_KEYCHAIN"
# Add certificate to keychain
security import $CERT -k "$MY_KEYCHAIN" -P "$CERT_PASSWORD" -A -T "/usr/bin/codesign" -T "/usr/bin/productsign"
# Enable codesigning from a non user interactive shell
security set-key-partition-list -S apple-tool:,apple:, -s -k $MY_KEYCHAIN_PASSWORD -D "${IDENTITY_CERTIFICATE}" -t private $MY_KEYCHAIN
Clean up Keychain
# Delete temporary keychain
security delete-keychain "$MY_KEYCHAIN"
# default again user login keychain
security list-keychains -d user -s login.keychain

Adding self-signed certificate as trusted in macOS doesn't work properly

I'm trying to create a simple Makefile command in order to install self-signed certificate for local development of an Angular app.
When I do this manually (by double-clicking on the certificate file, then opening a detail of it and setting everything to Always Trust) it works perfectly. On the other hand, the following command should do the same without any manual action, and as a matter of fact, it does (at least I couldn't find any difference in certificate details).
security add-trusted-cert -d -r trustRoot -k "/Users/${USER}/Library/Keychains/login.keychain" certificates/local.angular.domain.crt
I also tried it with a sudo command (the only difference when using sudo is that it doesn't open the native popup for password, which I prefer as the user can authenticate using a fingerprint).
Here's my whole Makefile command
install-certificate:
# generate certificate
git clone https://github.com/RubenVermeulen/generate-trusted-ssl-certificate.git
cd generate-trusted-ssl-certificate && \
sed -i.backup 's/CN.*/CN = local\.angular\.domain/g' ./openssl-custom.cnf && \
sed -i.backup 's/DNS\.1.*/DNS\.1 = \*\.local\.angular\.domain/g' ./openssl-custom.cnf && \
sed -i.backup 's/DNS\.2.*/DNS\.2 = local\.angular\.domain/g' ./openssl-custom.cnf && \
bash generate.sh
mkdir -p certificates
mv generate-trusted-ssl-certificate/server.key certificates/local.angular.domain.key
mv generate-trusted-ssl-certificate/server.crt certificates/local.angular.domain.crt
rm -rf generate-trusted-ssl-certificate
# add certificate as trusted
security add-trusted-cert -d -r trustRoot -k "/Users/${USER}/Library/Keychains/login.keychain" certificates/local.angular.domain.crt
grep -qxF '127.0.0.1 local.angular.domain' /etc/hosts || sudo -- sh -c "echo '127.0.0.1 local.angular.domain' >> /etc/hosts"
# clear DNS cache
sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder
This should be relatively easy to replicate as it generates the certificate itself and cleans up afterwards. Might be worth mentioning that the angular app runs on port 4200 (https://local.angular.domain:4200) which works smoothly when certificate is added manually. When added by the above command it shows the NET::ERR_CERT_AUTHORITY_INVALID. When I opened both certificates' details in chrome - they are the same. Thank you for any advice.
The web server needs the certificate as well as the associated private key.
But it looks like the command security add-trusted-cert does not import the private key (the .key file). You should consider using security import.

Set imported certificate to always be trusted in Mac OS X

I have generated a certificate in pfx format in Mac os X and imported it into system keychain using:
sudo security import server.pfx -k /Library/Keychains/System.keychain -P foobar
The problem is that all trusts are set to no value specified.
How can I set trust for code signing to Always trust using command line.
Here's what worked for me, it's very close to that traveling beard's answer. I'm using trustAsRoot instead of trustRoot.
With this change, in the Keychain Viewer, my cert now has "Always Trust" set. When I used trustRoot, the cert is added but with "Use System Default" set and the system default is to Never Trust.
sudo security add-trusted-cert -d -r trustAsRoot -k /Library/Keychains/System.keychain <certfile>
NOTE: The sudo will prompt for a password on the commandline and the gui will also prompt.
Nice, now I can import a dev cert on the command line with only a sudo passwd and not have to open that GUI!!
The -p option may be what you need. It can be specified more than once for each of the settings. I wish I knew how to deny one specific item while trusting another all in the same line.
sudo security add-trusted-cert -d -r trustRoot -p [option] -k /Library/Keychains/System.keychain <certificate>
-p options are ssl, smime, codeSign, IPSec, iChat, basic, swUpdate, pkgSign, pkinitClient, pkinitServer, timestamping, eap

Example for Mac OS X security delete-certificate -c <name>?

Short version: Please provide an example for security delete-certificate -c <name> ... (I tried security delete-certificate -c "Foo Certification Authority" and I tried wild cards.)
Long version:
What I'm trying to do: replace or overwrite an existing certificate.
Can someone provide an example of using security to get the "name" of a certificate and then using security delete-certificate -c <name> to delete it? I've tried a few things for <name> but haven't yet been able to give it something that matches the certificate that I want to remove.
Alternatively, if I use security add-trusted-cert -d -r trustRoot -k <keychain> <certificate> will that simply overwrite any existing certificate with the same name? If this is the case, then I guess I won't need to know how to delete the old one by name.
(I prefer dealing with the name instead of the SHA because it makes things more human-readable)
This answer, is almost verbatim from the stack apple site:
*Backup keychain before trying anything.
Listing root certificates:
sudo security dump-keychain /System/Library/Keychains/SystemRootCertificates.keychain
Look in the dump for names or SHA-1 hash values of certificates that you want to get rid of:
Usage: delete-certificate [-c name] [-Z hash] [-t] [keychain...]
-c Specify certificate to delete by its common name
-Z Specify certificate to delete by its SHA-1 hash value
-t Also delete user trust settings for this certificate The certificate to be deleted
must be uniquely specified either by a string found in its common name, or by its SHA-1 hash. If no keychains are specified to search, the default search list is used.
For example you could delete this chinese root certificates using this command:
sudo security delete-certificate -Z 8BAF4C9B1DF02A92F7DA128EB91BACF498604B6F /System/Library/Keychains/SystemRootCertificates.keychain
I think the -Z hash method is probably safer and would recommend doing it that way. The question you had about overwriting the certs is complicated because depending on the cert it's often not a one command takes care of all scenario. There's a post on the apple site with included screencasts of different ways to use (and not use) security and keychain.
Here's a method I use to purge old user certificates based on a certificate's common name.
In my particular case, my Mac user's are bound to Active Directory and they have "user certificates" installed.
The certificate's common name is the user's name, but not the user's "username".
In my environment, usernames are first.last.
So first, I get the path to the user's login.keychain and strip off the surrounding quotes then I pipe that into a string variable called "$Keychain_Name".
My script then retrieves the certificate's common name by fingering the currently logged in user, grepping for the "Name:" field and using awk to grab the desired info (First Last). That gets piped into the string "$Common_Name".
I then use security delete-certificate with the two string variables and voila, cert removed!
Script below...
#!/bin/sh
# CLEAR SCREEN
clear
echo "######################################################################"
echo "# Certificate Removal Script"
echo "# Written by Caine Hörr"
echo "# Written on Wednesday, July 17, 2013"
echo "# Last updated by Caine Hörr"
echo "# Last updated on Wednesday, July 17, 2013"
echo "######################################################################"
echo
echo
echo "Gathering Keychain Info"
Keychain_Name=$(security list-keychains | grep $(echo $USER) | tr -d '"')
echo
echo "Gathering Certificate Common Name Info"
Common_Name=$(finger $(echo $USER) | grep "Name:" | awk '{ print $4, $5 }')
echo
echo "Deleting Certificate $Common_Name from $Keychain_Name"
security delete-certificate -c "$Common_Name" $Keychain_Name
echo
echo "Process Complete"
exit
Hope this gives you some food for thought!

How To add-trusted-cert on a Mac Remotely (without user interaction)

Is it possible to add a trusted certificate on a Mac OS X 10.8.3 remotely? If so, how?
My current approach is to use the command below. Can it be tweaked so that it works remotely without user interaction?
security add-trusted-cert foo.cer
When I try the command above, I get SecTrustSettingsSetTrustSettings: The authorization was denied since no user interaction was possible.
My situation: the tool I'm using executes /bin/sh -xe bar.sh on the target machine and I have control over [1] which user it executes as and [2] the contents of bar.sh which currently has security add-trusted-cert foo.cer. Unlocking the keychain first does not appear to be the answer.
The command below works but the password can be seen by another user with ps and maybe even ends up in a commmand-line history as well. If there's a better answer that avoids this problem, most likely I'll mark that one as the accepted answer.
echo "password" | sudo -S /usr/bin/security add-trusted-cert -d -r trustRoot -k /path/to/keychain /path/to/cert
I got it from http://www.bynkii.com/archives/2009/04/stupid_cert_tricks.html

Resources