summaryrefslogtreecommitdiff
path: root/ca_maker_erg.sh
diff options
context:
space:
mode:
authorErg <uinarf@autistici.org>2024-11-27 17:45:03 +0100
committerErg <uinarf@autistici.org>2024-11-27 17:45:03 +0100
commit2fb55882d733d8c1e28a49153ef6c3449ebe7998 (patch)
tree5487847741f949a95b79a2f9f2046866c1dc9358 /ca_maker_erg.sh
parent6cb8d8a2a42d99e6440a2c0c74c08eca44c2d2df (diff)
downloadPico-master.tar.gz
Pico-master.tar.bz2
Pico-master.zip
RestructurisationHEADmaster
Diffstat (limited to 'ca_maker_erg.sh')
-rwxr-xr-xca_maker_erg.sh355
1 files changed, 355 insertions, 0 deletions
diff --git a/ca_maker_erg.sh b/ca_maker_erg.sh
new file mode 100755
index 0000000..db53278
--- /dev/null
+++ b/ca_maker_erg.sh
@@ -0,0 +1,355 @@
+#!/bin/bash
+usage() {
+ echo "Script name: $0";
+ echo "";
+ echo "Usage: $0 --key-type [ RSA | EC | EX25519 ]";
+ echo " --curve [ P-256 | P-384 | P512 ]";
+ echo " --rsa-bits [ 2048 | 4096 ]";
+ echo " --days <n>";
+ echo "";
+ echo "Options: ";
+ echo " --key-type [ RSA | EC | EC25519 ]";
+ echo " Note: Pico W can use EC or RSA keys only, not EC25519,";
+ echo " and Tasmota can only use 2048 bit RSA keys.";
+ echo " --curve [ P-256 | P-384 | P512 ]";
+ echo " --rsa-bits [ 2048 | 4096 ]";
+ echo " --days [ <integer> ]";
+ echo " --dir [ <mosquitto directory> ]";
+ echo " --output-format [ PEM | DER ]";
+ echo " --server_only [ True | False ]";
+ echo " --subjectAltName <subjectAltName>";
+ echo " Example subjectAltName: DNS.1:example.com,DNS.2:192.168.1.167,IP.1:192.168.1.167'";
+}
+
+# This creates a very slimline CA and Server cert with a full SAN multihost server.
+# The Mosquitto server requires keys and certs in PEM format, but it also exports
+# the CA Cert in DER for use in clients such as the Pico W
+TEMP="$(getopt -o h --long help,key-type:,curve:,rsa-bits:,ca_valid_for:,days:,dir:,output-format:,server_only:,subjectAltName: -- "$@")"
+
+eval set -- "$TEMP"
+
+if [ $# == 0 ] ; then
+ usage;
+ exit 1;
+fi
+
+mosquitto_dir="/home/erg/cert_test_1"
+key_type='EC'
+curve='P-256'
+rsa_bits='2048'
+# Choice to encrypt the CA Key or not? either BLANK or cypher (preferably aes-256-cbc)
+encryption=''
+# encryption='-aes-256-cbc'
+output_format='der'
+# Multiple DNS names and IP Addresses. Note mbedtls can't currently use data from IP fields,
+# but can read an IP from a DNS field, to the same effect.
+# Use as many unique names as you need, in the format DNS.1, DNS.2, DNS.3, IP.1, IP.2 etc.
+# subjectAltName='DNS.1:server_name,DNS.2:server_name.example.com,DNS.3:192.168.1.1,IP.1:192.168.1.1'
+subjectAltName='DNS.1:example.com,DNS.2:192.168.0.167,IP.1:192.168.0.167'
+ca_valid_for=3650
+certs_valid_for=365
+server_only="True"
+
+while true
+do
+ case "$1" in
+ -h|--help)
+ usage
+ exit 0;
+ ;;
+ # Note: Pico W can use EC or RSA keys only, not EC25519, and Tasmota can only use 2048 bit RSA keys.
+ # Default choice of Key Types: RSA || EC || ED25519
+ --key-type) key_type="$2"; shift 2;;
+ # Choice of NIST Curves for EC Keys: P-256 || P-384 || P-521
+ --curve) curve="$2"; shift 2;;
+ # Choice of Bits for RSA Keys: 2048 || 4096
+ --rsa-bits) rsa_bits="$2"; shift 2;;
+ # How many days is the CA Cert valid for:
+ --ca_valid_for) ca_valid_for="$2"; shift;;
+ # How many days is the Cert valid for:
+ --days) certs_valid_for="$2"; shift 2;;
+ # Mosquitto directory:
+ --dir) mosquitto_dir="$2"; shift 2;;
+ # Output format: PEM || DER
+ --output-format) output_format="$2"; shift 2;;
+ # Only generate server certificate and key, not the CA. Defaults to True.
+ --server_only) server_only="$2";shift 2;;
+ --subjectAltName) subjectAltName="$2";shift 2;;
+ -- ) shift; break;;
+ * ) break;;
+ esac
+done
+
+echo "subjectAltName you specified: $subjectAltName"
+
+if [ "$server_only" == "True" ] || [ "$server_only" == "true" ]|| [ "$server_only" == "Yes" ] || [ "$server_only" == 'yes' ]; then
+ server_only='True'
+else
+ server_only='False'
+fi
+
+# Mosquitto subdirectories:
+mosquitto_dir_ca="${mosquitto_dir}/certs/CA"
+mosquitto_dir_server="${mosquitto_dir}/certs/server"
+mosquitto_dir_csr="${mosquitto_dir}/certs/csr_files"
+ssl_ca_crt="${mosquitto_dir_ca}/ca_crt.${output_format}"
+ssl_ca_key="${mosquitto_dir_ca}/ca_key.${output_format}"
+
+# NOTE: If you need to create one or more client Keys and Certs in either PEM or DER format,
+# you can call the 'client_maker' script one or more times at the bottom of this script, so
+# just scroll right to the end to add the details. You can call 'client_maker' independantly
+# whenever you need more clients.
+
+#############################################################
+# Check passed option values sane #
+#############################################################
+echo "Checking if CA dir exists: $mosquitto_dir_ca ..."
+if [ ! -d $mosquitto_dir_ca ];then
+ echo "Certificate authority folder does not exist, exiting"
+ exit 1
+fi
+
+# Check CA key and cert exist:
+echo "Checking CA key and cert exist: ..."
+if [ ! -f ${ssl_ca_crt} ]; then # I: Double quote to prevent globbing and word splitting.
+ echo "CA certificate does not exist, exiting!"
+ exit 1
+fi
+if [ ! -f "${mosquitto_dir_ca}/ca_key.pem" ] && [ ! -f "${mosquitto_dir_ca}/ca_key.der" ]; then
+ echo "CA key does not exist, exiting!"
+ exit 1
+fi
+# Check CA certificate is still valid:
+# Date format we get from openssl:
+# Nov 18 13:47:56 2034 GMT
+# %b %d %H:%M:%S %Y %Z
+# compare dates from the CA cert and current one:
+echo "Checking CA certificate valid ..."
+cert_valid_until=$(openssl x509 -enddate -noout -in "${ssl_ca_crt}" | cut -d'=' -f2)
+echo "CA certificate valid until: ${cert_valid_until}"
+if [ ! $(($(date -d "$cert_valid_until" +"%s") > $(date +"%s"))) ];then
+ echo "CA certificate expired, exiting!"
+ exit 1
+fi
+# Check key type:
+if [ "$key_type" != 'EC' ] && [ "$key_type" != 'RSA' ] && [ "$key_type" != 'EC25519' ]; then
+ echo "Wrong key type specified: '$key_type'"
+ echo "Valid keys: [ EC | RSA | EC25519 ]"
+ usage
+ exit 1;
+fi
+
+# Check curve:
+if [ "$curve" != 'P-256' ] && [ "$curve" != 'P-384' ] && [ "$curve" != 'P-521' ]; then
+ echo "Wrong NIST curve specified: '$curve'"
+ echo "Curve must be one of: [ P-256 | P-384 | P-521 ]"
+ usage
+ exit 1;
+fi
+
+# Check RSA bits:
+if [ "$rsa_bits" != '2048' ] && [ "$rsa_bits" != '4096' ]; then
+ echo "Wrong RSA bits specified: '$rsa_bits'"
+ echo "Must be one of: [ 2048 | 4096 ]"
+ usage
+ exit 1;
+fi
+
+# Check days parameter is a number:
+if [ -n "$certs_valid_for" ] && [ "$certs_valid_for" -eq "$certs_valid_for" ] 2>/dev/null; then
+ echo "Certificate will be valid for: '$certs_valid_for' days"
+else
+ echo "Not a number: $certs_valid_for"
+ usage
+ exit 1;
+fi
+
+# Check output format:
+if [ ${output_format} == 'PEM' ] || [ ${output_format} == 'pem' ]; then # I: Double quote to prevent globbing and word splitting.
+ output_format="pem"
+elif [ $output_format == 'DER' ] || [ $output_format == 'der' ]; then # I: Double quote to prevent globbing and word splitting.
+ output_format="der"
+else echo "Incorrect certificate format type specified: '$output_format'";
+ usage
+ exit 1;
+fi
+
+
+############################################################
+# End of user defined variables
+############################################################
+
+
+# Set the algorithm
+algorithm="-algorithm ${key_type}"
+
+# Set the specific pkeyopt for the chosen algorithm (BLANK for ED25519)
+if [ "${key_type}" == "EC" ]; then
+ echo 'Creating EC Key ...'
+ pkeyopt="-pkeyopt ec_paramgen_curve:${curve}"
+elif [ "${key_type}" == "RSA" ]; then
+ echo 'Creating RSA Key ...'
+ pkeyopt="-pkeyopt rsa_keygen_bits:${rsa_bits}"
+elif [ "${key_type}" == "ED25519" ]; then
+ echo 'Creating ED25519 Key'
+ pkeyopt=""
+else
+ echo 'Key Type not found!'
+ exit 1
+fi
+
+############################################################
+# Backup existing certs and create dir structure
+############################################################
+
+# if certs dir already exists, rename it so we don't overwrite anything important
+# but if it doesn't, then redirect the 'No such file or directory' error to null
+time_stamp=$(date +"%Y-%m-%d_%H-%M")
+if [ ! -d "${mosquitto_dir_ca}" ]; then
+ mkdir -p "${mosquitto_dir_ca}-${time_stamp}" 2>/dev/null
+else
+ cp "${mosquitto_dir_ca}" "${mosquitto_dir_ca}-${time_stamp}" 2>/dev/null
+fi
+
+if [ ! -d "${mosquitto_dir_server}" ]; then
+ mkdir -p "${mosquitto_dir_server}-${time_stamp}" 2>/dev/null
+else
+ cp "${mosquitto_dir_server}" "${mosquitto_dir_server}-$time_stamp" 2>/dev/null
+fi
+
+# create a sensible directory structure to store everything if not exists:
+mkdir -p "${mosquitto_dir}"/certs/{DH,CA,server,clients,csr_files}
+
+
+###########################################################
+# dhparamfile Creation
+###########################################################
+
+# Output DH parameters for safe prime group ffdhe2048
+if [ "$server_only" == "True" ]; then
+openssl genpkey \
+ -genparam \
+ -algorithm DH \
+ -pkeyopt group:ffdhe2048 \
+ -out "$mosquitto_dir/certs/DH/dhp_ffdhe2048.pem"
+fi
+
+###########################################################
+# CA Creation
+###########################################################
+
+if [ "${server_only}" == 'True' ]; then
+openssl genpkey \
+ $algorithm $pkeyopt \
+ -outform pem \
+ -out "$mosquitto_dir_ca/ca_key.pem" "$encryption"
+fi
+
+
+# Self sign the CA cert
+
+if [ "${server_only}" == 'True' ]; then
+openssl req \
+ -x509 \
+ -new \
+ -key "$mosquitto_dir_ca/ca_key.pem" \
+ -days $ca_valid_for\
+ -subj '/CN=MQTT CA' \
+ -outform pem \
+ -out "$mosquitto_dir_ca/ca_crt.pem"
+fi
+
+###########################################################
+# Server Creation
+###########################################################
+
+# Create the Key
+openssl genpkey \
+ $algorithm $pkeyopt \
+ -outform pem \
+ -out "$mosquitto_dir_server/server_key.pem"
+
+# Create the certificate signing request (CSR)
+openssl req \
+ -new \
+ -subj "/CN=MQTT Server" \
+ -addext "subjectAltName = ${subjectAltName}" \
+ -nodes \
+ -key "$mosquitto_dir_server/server_key.pem" \
+ -out "$mosquitto_dir_server/server_req.csr"
+
+# Sign and authenticate it with the CA
+# We use copy_extensions to include the subjectAltNames from the CSR in the Server Cert
+echo "Sign and authenticate CSR with the CA ..."
+openssl x509 \
+ -req \
+ -in "$mosquitto_dir_server/server_req.csr" \
+ -copy_extensions copy \
+ -CA "${mosquitto_dir_ca}/ca_crt.pem" \
+ -CAkey "${mosquitto_dir_ca}/ca_key.pem" \
+ -CAcreateserial \
+ -days "${certs_valid_for}" \
+ -outform pem \
+ -out "$mosquitto_dir_server/server_crt.pem"
+
+
+###########################################################
+# Key and Cert Checking
+###########################################################
+
+# Examine the key to check that it looks OK
+openssl pkey \
+ -in "$mosquitto_dir_server/server_key.pem" \
+ -text \
+ -noout
+
+# Examine the CSR
+openssl req \
+ -in "$mosquitto_dir_server/server_req.csr" \
+ -noout \
+ -text
+
+# Validate the CA certificate
+openssl x509 \
+ -in "$mosquitto_dir_server/server_crt.pem" \
+ -text \
+ -noout
+
+#clean up after the server cert creation
+mv "$mosquitto_dir_server/server_req.csr" "$mosquitto_dir_csr"
+
+###########################################################
+# Key Export and Read Permissions fix
+###########################################################
+
+#We need to export a copy of our CA Certificate in DER format for micropython.
+openssl x509 \
+ -in "$mosquitto_dir_ca/ca_crt.pem" \
+ -out "$mosquitto_dir_ca/ca_crt.der" \
+ -outform "$output_format"
+
+# and save a copy of it somewhere useful
+cp \
+ "$mosquitto_dir_ca/ca_crt.der" \
+ "$mosquitto_dir/certs/clients"
+
+# but pem based clients need the pem version of it too
+cp \
+ "$mosquitto_dir_ca/ca_crt.pem" \
+ "$mosquitto_dir/certs/clients"
+
+# We also need to give read access to server_key.pem so it can be used by Mosquitto
+chmod 644 "$mosquitto_dir_server/server_key.pem"
+
+
+# move the ca_maker script to certs/CA and remove its execute permissions
+# to reduce the probability of running it by accident again
+# and overwriting everything in your certs directory
+#mv $mosquitto_dir/ca_maker $mosquitto_dir/certs/CA/ca_maker
+#chmod -x $mosquitto_dir/certs/CA/ca_maker
+
+# auto run the client_maker pem/der username
+# ./client_maker der pico
+#client_maker pem user2
+#client_maker pem user3
+#client_maker der user4