commit 9e8c8d4edb4efc2243c563be08c654e280be05f1 Author: Slawomir Koszewski Date: Wed Mar 4 05:41:01 2026 +0100 Initialized the repository. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1269488 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +data diff --git a/README.md b/README.md new file mode 100644 index 0000000..a0e3d02 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# Simple CA + diff --git a/cert-functions.sh b/cert-functions.sh new file mode 100644 index 0000000..e2afdd9 --- /dev/null +++ b/cert-functions.sh @@ -0,0 +1,176 @@ +function make_ca() { + # Use the provided directory argument or default to AZURITE_DIR if not provided + local CERT_DIR="$1" + local CA_NAME="$2" + + if [[ -z "$CERT_DIR" || -z "$CA_NAME" || ! -d "$CERT_DIR" ]]; then + echo "ERROR: Certificate directory $CERT_DIR does not exist." + return 1 + fi + + # Generate CA certificate and key if they don't exist + if [[ ! -f "$CERT_DIR/ca_cert.pem" || ! -f "$CERT_DIR/ca_key.pem" ]]; then + echo "Generating CA certificate '$CA_NAME' and key..." + if ! openssl req \ + -x509 \ + -newkey rsa:4096 \ + -keyout "$CERT_DIR/ca_key.pem" \ + -out "$CERT_DIR/ca_cert.pem" \ + -days 3650 \ + -nodes \ + -subj "/CN=${CA_NAME}" \ + -text \ + -addext "basicConstraints=critical,CA:TRUE,pathlen:0"; then + echo "ERROR: Failed to generate CA certificate and key." >&2 + return 1 + fi + fi + + return 0 +} + +function _is_ip() { + if [[ "$1" =~ ^[0-9]{1,3}(\.[0-9]{1,3}){3}$ ]]; then + return 0 + else + return 1 + fi +} + +function _is_dns() { + if [[ "$1" =~ ^[a-z0-9-]+(\.[a-z0-9-]+)*$ ]]; then + return 0 + else + return 1 + fi +} + +function make_server_cert() { + local CERT_DIR="$1" + local CERT_SUBJECT_NAME="$2" + shift 2 + + if [[ -z "$CERT_DIR" || ! -d "$CERT_DIR" ]]; then + echo "ERROR: Certificate directory $CERT_DIR does not exist." + return 1 + fi + + if [[ -z "$CERT_SUBJECT_NAME" ]]; then + echo "ERROR: Subject name is required." >&2 + return 1 + fi + + if ! _is_dns "$CERT_SUBJECT_NAME"; then + echo "ERROR: Invalid subject name '$CERT_SUBJECT_NAME'. Must be a valid DNS name." >&2 + return 1 + fi + + if [[ ! -f "$CERT_DIR/ca_cert.pem" || ! -f "$CERT_DIR/ca_key.pem" ]]; then + echo "ERROR: CA certificate and key not found in $CERT_DIR. Please call make_ca first." >&2 + return 1 + fi + + # Calculate the "account" name from the subject name, the hostname part before the first dot + local CERT_NAME="${CERT_SUBJECT_NAME%%.*}" + + # Start with the subjectAltName extension containing the main DNS name + local SANS=("DNS:${CERT_SUBJECT_NAME}") + + # Combine the remaining arguments into a single string for the subjectAltName extension + while [[ $# -gt 0 ]]; do + if _is_ip "$1"; then + SANS+=("IP:$1") + elif _is_dns "$1"; then + SANS+=("DNS:$1") + else + echo "ERROR: Invalid SAN entry '$1'" >&2 + return 1 + fi + shift + done + + # Join the SAN entries with commas for the OpenSSL command + local SANS_EXT="subjectAltName=$(IFS=,; echo "${SANS[*]}")" + + echo "Generating server certificate for '$CERT_SUBJECT_NAME' with SANs:" + for san in "${SANS[@]}"; do + echo " - $san" + done + + # Generate server certificate and key if they don't exist + if [[ ! -f "$CERT_DIR/${CERT_NAME}_cert.pem" || ! -f "$CERT_DIR/${CERT_NAME}_key.pem" ]]; then + echo "Generating server certificate and key..." + if ! openssl req \ + -newkey rsa:4096 \ + -keyout "$CERT_DIR/${CERT_NAME}_key.pem" \ + -nodes \ + -subj "/CN=${CERT_SUBJECT_NAME}" \ + -addext "basicConstraints=critical,CA:FALSE" \ + -addext "keyUsage=digitalSignature,keyEncipherment" \ + -addext "extendedKeyUsage=serverAuth,clientAuth" \ + -addext "$SANS_EXT" \ + | openssl x509 \ + -req \ + -CA "$CERT_DIR/ca_cert.pem" \ + -CAkey "$CERT_DIR/ca_key.pem" \ + -set_serial "0x$(openssl rand -hex 16)" \ + -copy_extensions copyall \ + -days 365 \ + -text \ + -out "$CERT_DIR/${CERT_NAME}_cert.pem"; then + echo "ERROR: Failed to generate server certificate and key." >&2 + return 1 + fi + fi + + return 0 +} + +function make_pfx() { + local CERT_DIR="$1" + local CERT_NAME="$2" + local PFX_PASSWORD="${3:-}" + + if [[ -z "$CERT_DIR" || ! -d "$CERT_DIR" ]]; then + echo "ERROR: Certificate directory $CERT_DIR does not exist." + return 1 + fi + + if [[ -z "$CERT_NAME" ]]; then + echo "ERROR: Certificate name is required." >&2 + return 1 + fi + + if [[ ! -f "$CERT_DIR/${CERT_NAME}_cert.pem" || ! -f "$CERT_DIR/${CERT_NAME}_key.pem" ]]; then + echo "ERROR: Server certificate and key not found in $CERT_DIR. Please call make_server_cert first." >&2 + return 1 + fi + + if [[ ! -f "$CERT_DIR/ca_cert.pem" || ! -f "$CERT_DIR/ca_key.pem" ]]; then + echo "ERROR: CA certificate and key not found in $CERT_DIR. Please call make_ca first." >&2 + return 1 + fi + + if [[ -z "$PFX_PASSWORD" ]]; then + PFX_PASSWORD="changeit" + fi + + if [[ ! -f "$CERT_DIR/${CERT_NAME}.pfx" ]]; then + echo -n "Generating PKCS#12 (PFX) file..." + if ! openssl pkcs12 \ + -export -out "$CERT_DIR/${CERT_NAME}.pfx" \ + -inkey "$CERT_DIR/${CERT_NAME}_key.pem" \ + -in "$CERT_DIR/${CERT_NAME}_cert.pem" \ + -certfile "$CERT_DIR/ca_cert.pem" \ + -password pass:"$PFX_PASSWORD"; then + echo "ERROR: Failed to generate PKCS#12 (PFX) file." >&2 + return 1 + fi + echo "done." + else + echo "PKCS#12 (PFX) file already exists, aborting generation." + return 1 + fi + + return 0 +}