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

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!

Related

"The output of `ssh-add -l` doesn't contain 'RSA'. Start the agent, add your keys?" in Docker

I am following this article and have included my AWS credentials. I installed several CLI things required, and now get:
$ ./trainer start 5
Greetings, cchilders/cchilders!
The output of `ssh-add -l` doesn't contain 'RSA'. Start the agent, add your keys?
I have already did eval $(ssh-agent) which doesn't help.
Run:
ssh-add
...to actually add a key with the default name (~/.ssh/id_rsa) to your agent (assuming you've created a key; if you haven't you'll need to go back and do that). If you created a key saved with a different name, pass that name on the ssh-add command line.
That said, on MacOS X, you generally shouldn't start ssh-agent yourself at all! The keychain on OS X fulfils the agent protocol.

scp script to multiple hosts that require a password

I am trying to write a shell script that will, given source file, target directory, and hosts file, scp a file to multiple hosts. I have gotten the script to work however there are a few issues but the file gets there. The only problem is the network I am working on requires a password for every remote. I need to do this to 150 plus remotes and need this to run automatically, possibly with a logging feature. If any one could help me out it would be greatly appreciated. Here's what I got so far...
# This is a script to copy files from one host to a group of hosts
# There are three variables accepted via commandline
# $1 = first parameter (/source_path/source_filename)
# $2 = second parameter (/target_directory/)
# $3 = third paramter (file that contains list of hosts)
SOURCEFILE=$1
TARGETDIR=$2
HOSTFILE=$3
if [ -f $SOURCEFILE ]
then
printf "File found, preparing to transfer\n"
while read server
do
scp -p $SOURCEFILE ${server}:$TARGETDIR
done < $HOSTFILE
else
printf "File \"$SOURCEFILE\" not found\n"
exit 1
fi
exit 0
SSH public-key authentication is a good solution here.
In short, run:
ssh-keygen -t dsa
To generate your public/private key pair.
Then, add ~/.ssh/id_dsa.pub to remote:~/.ssh/authorized_keys
Now, ssh will not ask for a password, since it will do a public-key authentication challenge instead.
I wrote an article here that describes this in some detail:
http://matt.might.net/articles/ssh-hacks/
You should not have to modify your script for this to work.

Specify private key in SSH as string

I can connect to a server via SSH using the -i option to specify the private key:
ssh -i ~/.ssh/id_dsa user#hostname
I am creating a script that takes the id_dsa text from the database but I am not sure how I can give that string to SSH. I would need something like:
ssh --option $STRING user#hostname
Where $STRING contains the value of id_dsa. I need to know the --option if there is one.
Try the following:
echo $KEY | ssh -i /dev/stdin username#host command
The key doesn't appear from a PS statement, but because stdin is redirected it's only useful for single commands or tunnels.
There is no such switch - as it would leak sensitive information. If there were, anyone could get your private key by doing a simple ps command.
EDIT: (because of theg added details in comment)
You really should store the key in to a temporary file. Make sure you set the permissions correctly before writing to the file, if you do not use command like mktemp to create the temporary file.
Make sure you run the broker (or agent in case of OpenSSH) process and load the key using <whatever command you use to fetch it form the database> | ssh-add -
Passing cryptokey as a string is not advisable but for the sake of the question, I would say I came across the same situation where I need to pass key as a string in a script. I could use key stored in a file too but the nature of the script is to make it very flexible, containing everything in itself was a requirement. so I used to assign variable and pass it and echo it as follows :
#!/bin/bash
KEY="${ YOUR SSH KEY HERE INSIDE }"
echo "${KEY}" | ssh -q -i /dev/stdin username#IP 'hostnamectl'
exit 0
Notes:
-q suppress all warnings
By the way , the catch here in above script, since we are using echo it will print the ssh key which is again not recommended , to hide that you can use grep to grep some anything which will not be printed for sure but still stdin will have the value from the echo. So the final cmd can be modified as follows :
#!/bin/bash
KEY="${ YOUR SSH KEY HERE INSIDE }"
echo "${KEY}" | grep -qw "less" | ssh -q -i /dev/stdin username#IP 'hostnamectl'
exit 0
This worked for me.
I was looking at the same problem. Adding private key content to ssh command via stdin did not work for me. I found out that its possible to add the private key file contents to ssh-agent using the command ssh-add. This will let you ssh into the remote host without explicitly specifying the identity file. My particular usecase was that I didn't want to store the SSH key in cleartext on my machine and was dynamically getting it from a secrets vault. This answer is mostly a collection of other answers on StackOverflow.
ssh-agent is a program to hold private keys used for public key
authentication. Through use of environment variables the agent can
be located and automatically used for authentication when logging
in to other machines using ssh
Source
This is what I have done.
First start the ssh-agent.
You can start it from your terminal by simply executing ssh-agent.
OPTIONAL: If you'd like to make sure ssh-agent is running on every login, you can add something like the following to your shell config.
This is what I have added to my ~/.bashrc file.
# set SSH_AUTH_SOCK env var to a fixed value
export SSH_AUTH_SOCK=~/.ssh/ssh-agent.sock
# test whether $SSH_AUTH_SOCK is valid
ssh-add -l 2>/dev/null >/dev/null
# if not valid, then start ssh-agent using $SSH_AUTH_SOCK
[ $? -ge 2 ] && ssh-agent -a "$SSH_AUTH_SOCK" >/dev/null
Source
(This particular snippet also makes sure new ssh-agent processes are not getting created when there's one already running.)
Now you have the ssh-agent running.
Since we're interested in loading SSH key as a string, I'll assume a scenario where private key contents has already been loaded in to a variable, $SSH_PRIVATE_KEY.
I can now add this Key contents to the ssh-agent by executing the following command.
ssh-add - <<< "${SSH_PRIVATE_KEY}"
This can just be added to the bashrc file as well.
You can confirm that your key has been added by listing all keys by executing ssh-agent -l. Aaand you're done now.
Try connecting to the remote host and you don't need a private key file.
ssh username#hostname
This does come with extra security risks. These are some I could think of:
Adding the private key to the ssh-agent will let any process on the machine access the key to authenticate remote hosts without explicitly providing any information.
Since the goal is to load Private key as a string, it will either be stored in a variable or the contents embedded directly in the command. This might make the key available in command history, the shell variable and other places.

Add a keychain to search list?

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.

How do you codesign framework bundles for the Mac App Store?

After a recent submission I have gotten the following error:
Invalid Signature - the nested app bundle (FooBar.app/Contents/Frameworks/GData.framework) is not signed, the signature is invalid, or it is not signed with an Apple submission certificate. Refer to the Code Signing and Application Sandboxing Guide for more information.
Invalid Signature - the nested app bundle (FooBar.app/Contents/Frameworks/Growl.framework) is not signed, the signature is invalid, or it is not signed with an Apple submission certificate. Refer to the Code Signing and Application Sandboxing Guide for more information.
Invalid Signature - the nested app bundle libcurl (FooBar.app/Contents/Frameworks/libcurl.framework) is not signed, the signature is invalid, or it is not signed with an Apple submission certificate. Refer to the Code Signing and Application Sandboxing Guide for more information.
So I signed all the framework bundles per Technote 2206:
codesign -f -v -s "3rd Party Mac Developer Application: Name" ./libcurl.framework/Versions/A/libcurl
codesign -f -v -s "3rd Party Mac Developer Application: Name" ./libcurl.framework/Versions/A/libssh2.1.dylib
codesign -f -v -s "3rd Party Mac Developer Application: Name" ./Growl.framework/Versions/A/Growl
codesign -f -v -s "3rd Party Mac Developer Application: Name" ./GData.framework/Versions/A/GData
Technote 2206 says:
Signing Frameworks
Seeing as frameworks are bundles it would seem logical to conclude that you can sign a framework directly. However, this is not the case. To avoid problems when signing frameworks make sure that you sign a specific version as opposed to the whole framework:
# This is the wrong way:
codesign -s my-signing-identity ../FooBarBaz.framework
# This is the right way:
codesign -s my-signing-identity ../FooBarBaz.framework/Versions/A
And when I try to verify the results, it looks good to me:
% codesign -vvv FooBar.app/Contents/Frameworks/libcurl.framework
FooBar.app/Contents/Frameworks/libcurl.framework: valid on disk
FooBar.app/Contents/Frameworks/libcurl.framework: satisfies its Designated Requirement
% codesign -vvv FooBar.app/Contents/Frameworks/Growl.framework
FooBar.app/Contents/Frameworks/Growl.framework: valid on disk
FooBar.app/Contents/Frameworks/Growl.framework: satisfies its Designated Requirement
For fun, I did try signing the framework bundle directly and it was still rejected. But that is exactly what the documentation said not to do.
Any guesses why that would be considered invalid? I am using the same cert that I use to code sign my app -- the one that has worked in the past.
My only guess would be something to do with the existing plists (do I need to own the identifiers in the framework's Info.plists?) or entitlements -- any suggestions?
Based on baptr’s answer, I have developed this shell script that codesigns all my frameworks and other binary resources/auxiliary executables (currently supported types: dylib, bundle, and login items):
#!/bin/sh
# WARNING: You may have to run Clean in Xcode after changing CODE_SIGN_IDENTITY!
# Verify that $CODE_SIGN_IDENTITY is set
if [ -z "${CODE_SIGN_IDENTITY}" ] ; then
echo "CODE_SIGN_IDENTITY needs to be set for framework code-signing!"
if [ "${CONFIGURATION}" = "Release" ] ; then
exit 1
else
# Code-signing is optional for non-release builds.
exit 0
fi
fi
if [ -z "${CODE_SIGN_ENTITLEMENTS}" ] ; then
echo "CODE_SIGN_ENTITLEMENTS needs to be set for framework code-signing!"
if [ "${CONFIGURATION}" = "Release" ] ; then
exit 1
else
# Code-signing is optional for non-release builds.
exit 0
fi
fi
ITEMS=""
FRAMEWORKS_DIR="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
if [ -d "$FRAMEWORKS_DIR" ] ; then
FRAMEWORKS=$(find "${FRAMEWORKS_DIR}" -depth -type d -name "*.framework" -or -name "*.dylib" -or -name "*.bundle" | sed -e "s/\(.*framework\)/\1\/Versions\/A\//")
RESULT=$?
if [[ $RESULT != 0 ]] ; then
exit 1
fi
ITEMS="${FRAMEWORKS}"
fi
LOGINITEMS_DIR="${TARGET_BUILD_DIR}/${CONTENTS_FOLDER_PATH}/Library/LoginItems/"
if [ -d "$LOGINITEMS_DIR" ] ; then
LOGINITEMS=$(find "${LOGINITEMS_DIR}" -depth -type d -name "*.app")
RESULT=$?
if [[ $RESULT != 0 ]] ; then
exit 1
fi
ITEMS="${ITEMS}"$'\n'"${LOGINITEMS}"
fi
# Prefer the expanded name, if available.
CODE_SIGN_IDENTITY_FOR_ITEMS="${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
if [ "${CODE_SIGN_IDENTITY_FOR_ITEMS}" = "" ] ; then
# Fall back to old behavior.
CODE_SIGN_IDENTITY_FOR_ITEMS="${CODE_SIGN_IDENTITY}"
fi
echo "Identity:"
echo "${CODE_SIGN_IDENTITY_FOR_ITEMS}"
echo "Entitlements:"
echo "${CODE_SIGN_ENTITLEMENTS}"
echo "Found:"
echo "${ITEMS}"
# Change the Internal Field Separator (IFS) so that spaces in paths will not cause problems below.
SAVED_IFS=$IFS
IFS=$(echo -en "\n\b")
# Loop through all items.
for ITEM in $ITEMS;
do
echo "Signing '${ITEM}'"
codesign --force --verbose --sign "${CODE_SIGN_IDENTITY_FOR_ITEMS}" --entitlements "${CODE_SIGN_ENTITLEMENTS}" "${ITEM}"
RESULT=$?
if [[ $RESULT != 0 ]] ; then
echo "Failed to sign '${ITEM}'."
IFS=$SAVED_IFS
exit 1
fi
done
# Restore $IFS.
IFS=$SAVED_IFS
Save it to a file in your project. I keep my copy in a Scripts subdirectory in my project’s root.
Mine is called codesign-frameworks.sh.
Add a “Run Script” build phase right after your “Copy Embedded Frameworks” build phase.
You can call it “Codesign Embedded Frameworks”.
Paste ./codesign-frameworks.sh (or whatever you called your script above) into the script editor text field. Use ./Scripts/codesign-frameworks.sh if you store the script in a subdirectory.
Build your app. All bundled frameworks will be codesigned.
Should you still get an “Identity: ambiguous (matches: …” error, please comment below. This should not happen anymore.
Updated 2012-11-14: Adding support for frameworks with special characters in their name (this does not include single quotes) to “codesign-frameworks.sh”.
Updated 2013-01-30: Adding support for special characters in all paths (this should include single quotes) to “codesign-frameworks.sh”.
Updated 2013-10-29: Adding experimental dylib support.
Updated 2013-11-28: Adding entitlements support. Improving experimental dylib support.
Updated 2014-06-13: Fixing codesigning issues with frameworks containing (nested) frameworks. This was done by adding -depth option to find, which causes find to do a depth-first traversal. This has become necessary, because of the issue described here. In short: a containing bundle can only be signed if its nested bundles are signed already.
Updated 2014-06-28: Adding experimental bundle support.
Updated 2014-08-22: Improving code and preventing failure to restore IFS.
Updated 2014-09-26: Adding support for login items.
Updated 2014-10-26: Quoting directory checks. This fixes the “line 31/42: too many arguments” errors and the resulting “ code object is not signed at all” error for paths including special characters.
Updated 2014-11-07: Resolving the ambiguous identity error (like “Mac Developer: ambiguous …”) when using automatic identity resolution in Xcode. You don’t have to explicitly set the identity anymore and can just use “Mac Developer”!
Updated 2015-08-07: Improving semantics.
Improvements welcome!
Your comment shows you signed the objects within the bundle's version directory. The Technote shows to sign the directory itself.
The following matches the Technote better:
codesign -f -v -s "3rd Party Mac Developer Application: Name" ./libcurl.framework/Versions/A
codesign -f -v -s "3rd Party Mac Developer Application: Name" ./Growl.framework/Versions/A
codesign -f -v -s "3rd Party Mac Developer Application: Name" ./GData.framework/Versions/A
This is how I fixed it;
Enter to the build settings of your target
Find the line "Other Code Signing Flags"
Enter --deep value to the release parameter
Close Xcode
Enter to the derived data folder on your Mac and delete the old derived data (default path is: /Users/YOUR_USER_NAME/Library/Developer/Xcode/DerivedData)
Open Xcode and build
After the build archive and submit the app again...
One thing I don't see mentioned here is that you need to have your Info.plist inside /Resources inside the versioned framework directory. Otherwise you'll get the "bundle format unrecognized, invalid, or unsuitable" error when you try to sign the versioned directory.
I provided a more extended answer here: How to Codesign Growl.framework for Sandboxed Mac App

Resources