Skip to content

Instantly share code, notes, and snippets.

@jamesthomasonjr
Created February 21, 2020 16:27
Show Gist options
  • Save jamesthomasonjr/8e2d25241f9bec0a12368ec2bdd85ccd to your computer and use it in GitHub Desktop.
Save jamesthomasonjr/8e2d25241f9bec0a12368ec2bdd85ccd to your computer and use it in GitHub Desktop.
Easily Generate & Trust a Self Signed Certificate on OS X
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
# Configuration
# Certifiate TTL
DAYS=3650
# RSA Encryption Bits
BITS=2048
# Hostnames
HOSTS=()
hash jq 2>/dev/null || {
echo >&2 "jq is required to run this script. Aborting."
exit 1
}
echo "What hostnames should this certificate be generated for?"
echo "Leave blank to default to only localhost. Terminate list with an empty line."
read -p "hostname [localhost]: " hostname
if [ -z "$hostname" ]; then
HOSTS=( 'localhost' )
else
while [ ! -z "$hostname" ]; do
HOSTS+=( $hostname )
read -p "alternate name [press enter to skip]: " hostname
done
fi
LOCATION_INFORMATION=$(curl https://ipapi.co/json/)
LOCATION_COUNTRY=$(echo $LOCATION_INFORMATION | jq --raw-output ".country")
LOCATION_REGION=$(echo $LOCATION_INFORMATION | jq --raw-output ".region")
LOCATION_CITY=$(echo $LOCATION_INFORMATION | jq --raw-output ".city")
# Create initial config
CONFIG=$(cat <<EOF
[ req ]
default_bits = $BITS
prompt = no
default_md = sha256
distinguished_name = dn
req_extensions = req_ext
[ dn ]
C = $LOCATION_COUNTRY
ST = $LOCATION_REGION
L = $LOCATION_CITY
O = $(whoami)
OU = dev
CN = ${HOSTS[0]}
emailAddress = $(whoami)@$(hostname)
[ req_ext ]
subjectAltName = @alt_names
[ alt_names ]
EOF
)
# Add additional hosts to config
for i in ${!HOSTS[@]}; do
CONFIG+=$'\n'"DNS.$((${i} + 1)) = ${HOSTS[$i]}"
done
echo
echo "Creating Configuration File..."
echo "${CONFIG}" >> "${HOSTS[0]}.csr.config"
echo
echo "Creating Certificate Key..."
openssl genrsa -out ${HOSTS[0]}.key $BITS
echo
echo "Creating Certificate Signing Request..."
openssl req -new -sha256 -out ${HOSTS[0]}.csr -key ${HOSTS[0]}.key -config ${HOSTS[0]}.csr.config
echo
echo "Creating Certificate..."
openssl x509 -req -sha256 -days $DAYS -in ${HOSTS[0]}.csr -signkey ${HOSTS[0]}.key -out ${HOSTS[0]}.crt -extensions req_ext -extfile ${HOSTS[0]}.csr.config
# The security CLI app doesn't quite work for trusting certs, so we use OS X APIs through Swift...
# And the OS X API requires DER format.
echo
echo "Converting from PEM format to DER format..."
openssl x509 -inform PEM -outform DER -in ${HOSTS[0]}.crt -out ${HOSTS[0]}.der.crt
echo
echo "Certificate generated!"
echo "Run the 'trust-cert' script to add the certificate to your keychain. (You will be asked for your password)"
echo
echo "Automatically run trust-cert script for ${HOSTS[0]}.der.crt?"
options=("Yes" "No")
select opt in "${options[@]}"; do
if [ "${opt}" = "Yes" ]; then
(
trust_cert_script="$(dirname ${BASH_SOURCE[0]})/trust-cert"
$trust_cert_script ${HOSTS[0]}.der.crt
)
else
break
fi
done
#!/usr/bin/env swift
// This script is written in swift because the CLI app (/usr/bin/security) doesn't seem to work
import Foundation
import Security
if CommandLine.argc < 2 {
print("No certificate file passed!")
exit(1)
}
let filePath = CommandLine.arguments[1]
var data:NSData
do {
let file:URL = URL(fileURLWithPath: filePath)
data = try NSData(contentsOf: file)
} catch {
print("Couldn't get data from file: \(error).")
exit(1)
}
let certificate:SecCertificate! = SecCertificateCreateWithData(nil, data)
if (certificate == nil) {
print("Certificate was invalid.")
exit(1)
}
let certificates:Array<SecCertificate> = [certificate]
let domain:SecTrustSettingsDomain = SecTrustSettingsDomain.user
let trustSettings:CFTypeRef? = nil // Null TrustSettings = Always Trust
let keychain:SecKeychain? = nil // Null Keychain = Default (usually login)
var status = SecTrustSettingsSetTrustSettings(certificate, domain, nil)
if (status != errSecSuccess) {
let message:Any = SecCopyErrorMessageString(status, nil) as Any
print(message)
exit(status)
}
status = SecCertificateAddToKeychain(certificate, keychain)
if (status == errSecDuplicateItem) {
status = errSecSuccess;
}
if (status != errSecSuccess) {
let message:Any = SecCopyErrorMessageString(status, nil) as Any
print(message)
exit(status)
}
exit(status)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment