316 lines
7.4 KiB
Bash
Executable file
316 lines
7.4 KiB
Bash
Executable file
#!/usr/bin/bash
|
|
set -euo pipefail
|
|
|
|
term_blue='\033[1;34m'
|
|
term_green='\033[0;32m'
|
|
term_yellow='\033[0;33m'
|
|
term_red='\033[0;31m'
|
|
term_reset='\033[0m'
|
|
|
|
cat <<EOF
|
|
|
|
==========================================
|
|
| |
|
|
| .NET Gen-Devcerts - v1.0.0 |
|
|
| |
|
|
| Copyright (c) 2026 Zervó Zadachin. |
|
|
| All Rights Reserved. |
|
|
| |
|
|
==========================================
|
|
|
|
EOF
|
|
|
|
SAVE_LOCAL=0
|
|
QUIET=0
|
|
NO_CLEAN=0
|
|
IGNORE_ERROR=0
|
|
|
|
if [ -z "${SSL_CERT_DIR+x}" ]; then
|
|
export SSL_CERT_DIR="$HOME/.aspnet/dev-certs/trust:/usr/lib/ssl/certs"
|
|
fi
|
|
|
|
# ========================
|
|
# COMMON FUNCTIONS
|
|
# ========================
|
|
|
|
# Print command usage
|
|
_usage() {
|
|
cat <<EOF
|
|
Usage: $0 [options]
|
|
|
|
Generates a new valid ASP.NET Core self-signed certificate for localhost.
|
|
Clears any existing certs in .NET certificate stores.
|
|
The new certificate will be imported into the system certificate store.
|
|
|
|
Options:
|
|
--help Show this usage information.
|
|
--save Copy the generated certificate to the home directory.
|
|
--quiet Reduce logging verbosity to only warnings and errors.
|
|
--noclean Skips the pre-cleaning of dotnet cert stores.
|
|
--force Do not exit on non-fatal errors. Causes unpredictable behaviour.
|
|
EOF
|
|
exit 1
|
|
}
|
|
|
|
# Show an INFO message
|
|
# $1: message string
|
|
_msg_info() {
|
|
local _msg="${1}"
|
|
if [ "$QUIET" = 0 ]; then
|
|
printf '[Gen-Devcerts] %bINFO%b: %s\n' "${term_blue}" "${term_reset}" "${_msg}"
|
|
fi
|
|
}
|
|
|
|
# Show a WARNING message
|
|
# $1: message string
|
|
_msg_warning() {
|
|
local _msg="${1}"
|
|
printf '[Gen-Devcerts] %bWARNING%b: %s\n' "${term_yellow}" "${term_reset}" "${_msg}" >&2
|
|
}
|
|
|
|
# Show an ERROR message then exit with status
|
|
# $1: message string
|
|
# $2: exit code number (with 0 does not exit)
|
|
_msg_error() {
|
|
local _msg="${1}"
|
|
local _error=${2}
|
|
printf '[Gen-Devcerts] %bERROR%b: %s\n' "${term_red}" "${term_reset}" "${_msg}" >&2
|
|
if ((_error > 0)); then
|
|
exit "${_error}"
|
|
fi
|
|
}
|
|
|
|
# ========================
|
|
# MAIN LOGIC
|
|
# ========================
|
|
|
|
# Parse options
|
|
OPTS=$(getopt -o sqnfh --long save,quiet,noclean,force,help -- "$@")
|
|
if [[ $? -ne 0 ]]; then
|
|
_msg_info "Use --help for help."
|
|
_msg_error "Invalid options"
|
|
fi
|
|
|
|
eval set -- "$OPTS"
|
|
|
|
while true; do
|
|
case "$1" in
|
|
--save | -s)
|
|
SAVE_LOCAL=1
|
|
shift
|
|
;;
|
|
--quiet | -q)
|
|
QUIET=1
|
|
shift
|
|
;;
|
|
--noclean | -n)
|
|
NO_CLEAN=1
|
|
shift
|
|
;;
|
|
--force | -f)
|
|
IGNORE_ERROR=1
|
|
shift
|
|
;;
|
|
--help | -h)
|
|
_usage
|
|
exit 1
|
|
;;
|
|
--)
|
|
shift
|
|
break
|
|
;;
|
|
*)
|
|
_msg_info "Use --help for help."
|
|
_msg_error "Unknown option: $1" 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# Detect distro
|
|
. /etc/os-release
|
|
_msg_info "Found distribution '$ID'"
|
|
case "$ID" in
|
|
debian | ubuntu)
|
|
PLATFORM_SCRIPT="debian"
|
|
;;
|
|
arch)
|
|
PLATFORM_SCRIPT="arch"
|
|
;;
|
|
fedora | rhel | centos)
|
|
PLATFORM_SCRIPT="fedora"
|
|
;;
|
|
*)
|
|
PLATFORM_SCRIPT=""
|
|
if [ "$IGNORE_ERROR" = 1 ]; then
|
|
_msg_warning "Running on unsupported distribution. Platform-specific scripts will not be executed."
|
|
else
|
|
_msg_error "Running on unsupported distribution." 1
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
# Create working directory
|
|
_msg_info "Creating working directory"
|
|
WORK_DIR="$(mktemp -d)"
|
|
_msg_info "Temp WorkDir at: '$WORK_DIR'"
|
|
|
|
# Set file paths
|
|
|
|
KEYFILE="$WORK_DIR/dotnet-devcert.key"
|
|
CRTFILE="$WORK_DIR/dotnet-devcert.crt"
|
|
PFXFILE="$WORK_DIR/dotnet-devcert.pfx"
|
|
|
|
NSSDB_PATHS="$HOME/.pki/nssdb \
|
|
$HOME/snap/chromium/current/.pki/nssdb \
|
|
$HOME/snap/postman/current/.pki/nssdb"
|
|
|
|
CONF_PATH="$WORK_DIR/localhost.conf"
|
|
|
|
# Post-variable functions
|
|
cleanup() {
|
|
_msg_info "Cleaning up"
|
|
rm -R $WORK_DIR
|
|
}
|
|
|
|
configure_nssdb() {
|
|
certutil -d sql:"$1" -D -n dotnet-devcert
|
|
certutil -d sql:"$1" -A -t "CP,," -n dotnet-devcert -i $CRTFILE
|
|
}
|
|
|
|
# Write config file
|
|
_msg_info "Writing certificate config"
|
|
cat >>$CONF_PATH <<EOF
|
|
[req]
|
|
prompt = no
|
|
default_bits = 2048
|
|
distinguished_name = subject
|
|
req_extensions = req_ext
|
|
x509_extensions = x509_ext
|
|
|
|
[ subject ]
|
|
commonName = localhost
|
|
|
|
[req_ext]
|
|
basicConstraints = critical, CA:true
|
|
subjectAltName = @alt_names
|
|
|
|
[x509_ext]
|
|
basicConstraints = critical, CA:true
|
|
keyUsage = critical, keyCertSign, cRLSign, digitalSignature,keyEncipherment
|
|
extendedKeyUsage = critical, serverAuth
|
|
subjectAltName = critical, @alt_names
|
|
1.3.6.1.4.1.311.84.1.1 = ASN1:UTF8String:ASP.NET Core HTTPS development certificate # Needed for import with dotnet dev-certs
|
|
|
|
[alt_names]
|
|
DNS.1 = localhost
|
|
EOF
|
|
|
|
# Remove old certificates
|
|
if [ "$NO_CLEAN" = 1 ]; then
|
|
_msg_warning "Skipping certificate pre-cleaning"
|
|
else
|
|
_msg_info "Removing old certificates"
|
|
dotnet dev-certs https --clean || true
|
|
rm -rf ~/.dotnet/devcrt/* || true
|
|
rm -rf ~/.aspnet/https/* || true
|
|
rm -f ~/.dotnet/corefx/cryptography/x509stores/my/* || true
|
|
fi
|
|
|
|
# Generate new certificates
|
|
_msg_info "Generating new certificates"
|
|
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout $KEYFILE -out $CRTFILE -config $CONF_PATH --passout pass:
|
|
openssl pkcs12 -export -out $PFXFILE -inkey $KEYFILE -in $CRTFILE --passout pass:
|
|
|
|
# Configure NSSDBs
|
|
_msg_info "Configuring NSSDBs"
|
|
for NSSDB in $NSSDB_PATHS; do
|
|
if [ -d "$NSSDB" ]; then
|
|
_msg_info "Configuring NSSDB for '$NSSDB'"
|
|
configure_nssdb "$NSSDB"
|
|
fi
|
|
done
|
|
|
|
# Enable sudo append if necessary
|
|
SUDO=''
|
|
if [ "$(id -u)" -ne 0 ]; then
|
|
SUDO='sudo'
|
|
fi
|
|
|
|
# Import certificate to dotnet
|
|
_msg_info "Importing certificate with dotnet dev-certs"
|
|
dotnet dev-certs https --clean --import $PFXFILE -p ""
|
|
|
|
# Save local home copy if enabled
|
|
if [ "$SAVE_LOCAL" = 1 ]; then
|
|
cp $CRTFILE $HOME
|
|
_msg_info "Saved certificate to $HOME/$(basename $CRTFILE)"
|
|
cp $PFXFILE $HOME
|
|
_msg_info "Saved certificate to $HOME/$(basename $PFXFILE)"
|
|
fi
|
|
|
|
# Main logic, specifically platform script execution, continues after platform script definitions.
|
|
|
|
# ========================
|
|
# PLATFORM SCRIPTS
|
|
# ========================
|
|
|
|
postrun_arch() {
|
|
local OLD_CRT=/etc/ca-certificates/trust-source/localhost.p11-kit
|
|
if [ -f "$OLD_CRT" ]; then
|
|
_msg_info "Removing old certificate from trust store"
|
|
$SUDO rm "$OLD_CRT" || true
|
|
fi
|
|
|
|
_msg_info "Adding new certificate to trust store"
|
|
$SUDO trust anchor --store $CRTFILE
|
|
$SUDO trust extract-compat
|
|
|
|
local FINGERPRINT="$(openssl x509 -noout -fingerprint -sha1 -inform pem -in /etc/ca-certificates/trust-source/localhost.p11-kit)"
|
|
_msg_info "Stored: $FINGERPRINT"
|
|
}
|
|
|
|
postrun_debian() {
|
|
_msg_info "Removing old certificate from system"
|
|
$SUDO rm /etc/ssl/certs/dotnet-devcert.pem || true
|
|
|
|
_msg_info "Installing new certificate on system"
|
|
$SUDO cp $CRTFILE "/usr/local/share/ca-certificates"
|
|
$SUDO update-ca-certificates
|
|
|
|
local FINGERPRINT="$(openssl x509 -noout -fingerprint -sha1 -inform pem -in /usr/local/share/ca-certificates/aspnet/https.crt)"
|
|
_msg_info "Stored: $FINGERPRINT"
|
|
}
|
|
|
|
postrun_fedora() {
|
|
_msg_info "Adding new certificate to trust store"
|
|
$SUDO cp $CRTFILE "/etc/pki/ca-trust/source/anchors/"
|
|
$SUDO update-ca-trust
|
|
}
|
|
|
|
# ========================
|
|
# POST-RUN LOGIC
|
|
# ========================
|
|
|
|
_msg_info "Running post-gen platform scripts"
|
|
|
|
# Run platform script here
|
|
case "$PLATFORM_SCRIPT" in
|
|
debian)
|
|
postrun_debian
|
|
;;
|
|
arch)
|
|
postrun_arch
|
|
;;
|
|
fedora)
|
|
postrun_fedora
|
|
;;
|
|
*)
|
|
_msg_warning "Post-gen skipped: unknown distribution"
|
|
;;
|
|
esac
|
|
|
|
# Perform cleanup
|
|
cleanup
|
|
|
|
# Announce completion
|
|
printf "%bCertificates (re)generated successfully! %b\n" "${term_green}" "${term_reset}"
|