One thing at a time
Importing and sharing iOS/macOS certificates and keys required for AppStore distribution of application can be pain 🔥 as we know it.
with a little command line, I can help myself a little bit.
Here, I'm building command line shell script that will load certificates if necessary.
What do I need:
- certificate file
- private key file
- certificate identifier
Prepare
Download certificate file
Download certificate from https://developer.apple.com/account/ios/certificate/
see "Certificate identifier" section for more.
Export private key
The private key is probably in my Keychain. It was created when I created Certificate Signing Request (CSR) for certificate, as described at developer portal:
Search for private key in Keychain
then export key as Personal Information Exchange (.p12) file type.
and save next to certificate file.
As a result, I have two files saved locally:
- G8DZVTHQJC.cer
- G8DZVTHQJC.p12
Obtain certificate identifier
This step is optional, but I think it's good to keep things in order. Certificate have its own, unique identifier used by developer portal. This number is not exposed; I found it useful to identify certificates, though.
When it comes to extracting certificate identifier, it's not the easiest part. Unfortunately, the downloaded file is always named "ios_distribution.cer" 🤔 I will use some hackery to solve this puzzle.
"Copy Link Address" where I can find all identifiers I need:
...&teamId=67RAWLRX93&certificateId=G8DZVTHQJC&type=R58UK2EWSO
My certificate identifier is: G8DZVTHQJC
Script
With those two files, I can automate importing certificate and key to my local account.
First check if a certificate is already loaded, then import or discard.
With this command, I get fingerprint I can use to identify it in Keychain
$ openssl x509 -inform DER -in G8DZVTHQJC.cer -noout -fingerprint | sed 's/\://g' | sed 's/.*=//g'
> B373427D867D91A8C3EBE3EF55D239C126A0F2B4
then just import certificate and key
$ security -q import G8DZVTHQJC.cer -A -k ~/Library/Keychains/login.keychain -T /usr/bin/codesign -T /usr/bin/security 2>/dev/null
$ security -q import G8DZVTHQJC.p12 -A -k ~/Library/Keychains/login.keychain -T /usr/bin/codesign -T /usr/bin/security 2>/dev/null
and the script (gist)
#!/bin/sh
# Usage: import.sh "directory/project/distribution/files" "G8DZVTHQJC"
ROOT_PATH="$1"
CER_FILENAME="$2".cer
P12_FILENAME="$2".p12
CERT_SHA1=`openssl x509 -inform DER -in $ROOT_PATH/$CER_FILENAME -noout -fingerprint | sed 's/\://g' | sed 's/.*=//g'`
if security find-identity -v -p codesigning | grep $CERT_SHA1 > /dev/null; then
echo "Found valid certificate in Keychain"
else
echo "Importing $CER_FILENAME"
security -q import $ROOT_PATH/$CER_FILENAME -A -k ~/Library/Keychains/login.keychain -T /usr/bin/codesign -T /usr/bin/security 2>/dev/null
echo "Importing $P12_FILENAME"
security -q import $ROOT_PATH/$P12_FILENAME -A -k ~/Library/Keychains/login.keychain -T /usr/bin/codesign -T /usr/bin/security 2>/dev/null
fi
echo "done."
Outstanding problem is that private key has to be shared among the developers. It's not safe to put it in project repo. It's a good idea to have separated git repository you can fetch and use files, then delete. The best option is add one security layer. Either create private key with a password (do not use an empty password) or encrypt files in external git repository using shared password. To do that I can use formula below and add it to the script:
encrypt:
$ openssl aes-256-cbc -in G8DZVTHQJC.p12 -out G8DZVTHQJC.p12.enc
decrypt:
$ openssl aes-256-cbc -d -in G8DZVTHQJC.p12.enc -out G8DZVTHQJC.p12
Installation
- create directory
projectname/distribution
- download distribution certificate and save as
projectname/distribution/TR234RGHSE.cer
- export private key and save as
projectname/distribution/TR234RGHSE.p12
- run import script
import.sh projectname/distribution TR234RGHSE
Summary
Shell script and stored certificates may automate in bootstrapping shared project.
I may use fastlane/match to archive the same goal. Simple script approach is a just simple tool to do one thing at a time, right.
What do you think? Let me know.