Simplifying Unifi SSL/TLS Certificate Management for Enhanced Security

In today’s digital landscape, where cybersecurity is paramount, managing SSL/TLS certificates for network devices like the Unifi Dream Router has become critical. These certificates not only encrypt the Unifi user interface but also secure the Wi-Fi guest access page, ensuring a safe browsing experience for users.

Understanding the Importance of SSL/TLS Certificates

SSL/TLS certificates play a vital role in securing network communications by encrypting data exchanged between devices and servers. For Unifi devices, these certificates are instrumental in safeguarding sensitive information accessed through the user interface and ensuring the integrity of the Wi-Fi guest access portal.

Introducing the Unifi Device SSLer Script

The Unifi Device SSLer script, version 0.96c (BETA), offers a robust solution for managing SSL/TLS certificates on Unifi devices. This innovative tool, meticulously crafted by Justin @ FalconTechnix, aka REAvER @ DOWNFALL.us, simplifies the often complex process of certificate management, making it accessible to users of all skill levels.

Streamlining Certificate Management

With the Unifi Device SSLer script, users can effortlessly obtain and renew SSL/TLS certificates for their Unifi devices. The script automates the retrieval process using Certbot, a widely recognized certificate management tool, ensuring seamless integration with Let’s Encrypt, a free, automated, and open certificate authority.

Enhanced Security Features

One of the standout features of the Unifi Device SSLer script is its ability to verify certificate validity, providing users with peace of mind regarding their network’s security. By displaying essential certificate information and conducting thorough verification checks, the script ensures that only valid and trusted certificates are utilized, mitigating potential security risks.

Future Developments and Automation

As the Unifi Device SSLer script evolves, users can expect additional features and enhanced automation capabilities. Future updates will focus on further streamlining the certificate management process, reducing manual intervention, and improving overall usability. Stay tuned for updates and enhancements designed to make SSL/TLS certificate management even more seamless and user-friendly.

Sleepless “Knight”

This morning, fueled by a bout of insomnia, I delved deep into the Unifi SSL/TLS certificate management project, dedicating a solid six hours to making significant progress. Despite the sleepless night, I found myself immersed in the task, fueled by a relentless determination to overcome any challenges that came my way. Harnessing the quiet solitude of the early morning hours, I navigated through intricate lines of code, fine-tuning and optimizing the Unifi Device SSLer script to enhance its functionality and user experience. With each passing hour, I made substantial headway, moving closer to my goal of simplifying SSL/TLS certificate management for Unifi devices. Eventually, this endeavor led to the birth of what I’ve dubbed SSLer—a tool poised to revolutionize the management of SSL/TLS certificates across the Unifi ecosystem.

Conclusion

In an era where cybersecurity is paramount, managing SSL/TLS certificates for Unifi devices is essential for safeguarding sensitive information and maintaining a secure network environment. The Unifi Device SSLer script offers a comprehensive solution for certificate management, simplifying the process and enhancing security effortlessly. With its intuitive interface and robust features, the script empowers users to take control of their network’s security with confidence.

For further information on Unifi SSL/TLS certificate management and best practices, consider exploring resources from reputable sources like Let’s Encrypt and the Unifi community forums.

Remember, a secure network starts with effective certificate management. Stay protected, stay secure with the Unifi Device SSLer script.

Keywords: Unifi SSL/TLS certificate management, Unifi Device SSLer script, SSL/TLS certificate automation, network security, Let’s Encrypt, Wi-Fi guest access security

The Unifi Device SSLer script can be found below.

#!/bin/bash
SCRIPT_VERSION='0.96c'
clear
MOTD="BY Justin @ FalconTechnix AKA REAvER @ DOWNFALL.us"
# Colors for formatting output
RED='\033[1;31m'
GREEN='\033[1;32m'
YELLOW='\033[1;33m'
BLUE='\033[1;34m'
PURPLE='\033[1;35m'
CYAN='\033[1;36m'
NC='\033[0m' # No Color
# Function to generate a random color code
random_color() {
    colors=($RED $GREEN $YELLOW $BLUE $PURPLE $CYAN)
    index=$((RANDOM % ${#colors[@]}))
    echo "${colors[$index]}"
}

# Rainbow colored ASCII art
echo -e "${RED}███████╗ █████╗ ██╗      ██████╗ ██████╗ ███╗   ██╗${NC}"
echo -e "${ORANGE}██╔════╝██╔══██╗██║     ██╔════╝██╔═══██╗████╗  ██║${NC}"
echo -e "${YELLOW}█████╗  ███████║██║     ██║     ██║   ██║██╔██╗ ██║${NC}"
echo -e "${GREEN}██╔══╝  ██╔══██║██║     ██║     ██║   ██║██║╚██╗██║${NC}"
echo -e "${BLUE}██║     ██║  ██║███████╗╚██████╗╚██████╔╝██║ ╚████║${NC}"
echo -e "${PURPLE}╚═╝     ╚═╝  ╚═╝╚══════╝ ╚═════╝ ╚═════╝ ╚═╝  ╚═══╝${NC}"
echo -e "${CYAN}████████╗███████╗ ██████╗██╗  ██╗███╗   ██╗██╗██╗  ██╗${NC}"
echo -e "${RED}╚══██╔══╝██╔════╝██╔════╝██║  ██║████╗  ██║██║╚██╗██╔╝${NC}"
echo -e "${ORANGE}   ██║   █████╗  ██║     ███████║██╔██╗ ██║██║ ╚███╔╝${NC}"
echo -e "${YELLOW}   ██║   ██╔══╝  ██║     ██╔══██║██║╚██╗██║██║ ██╔██╗${NC}"
echo -e "${GREEN}   ██║   ███████╗╚██████╗██║  ██║██║ ╚████║██║██╔╝ ██╗${NC}"
echo -e "${BLUE}   ╚═╝   ╚══════╝ ╚═════╝╚═╝  ╚═╝╚═╝  ╚═══╝╚═╝╚═╝  ╚═╝${NC}"
echo -e "${RED}Unifi Device SSLer${GREEN} Version${ORANGE}${PURPLE} ${SCRIPT_VERSION}${CYAN}(BETA)${NC}"
# Iterate over each character in the MOTD, colorize and display it
for ((i = 0; i < ${#MOTD}; i++)); do
    color=$(random_color)
    echo -ne "${color}${MOTD:$i:1}${NC}"
done
echo ""
echo ""



# Get the directory of the script
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

# Unifi Core path
UNIFI_CORE_PATH="/data/unifi-core/config/"

# Unifi Core cert name
UNIFI_CORE_CERT="unifi-core.crt"
UNIFI_CORE_KEY="unifi-core.key"

# Unifi Core certificate and key paths
UNIFI_CORE_CERT_PATH="${UNIFI_CORE_PATH}/${UNIFI_CORE_CERT}"
UNIFI_CORE_KEY_PATH="${UNIFI_CORE_PATH}/${UNIFI_CORE_KEY}"

# File to store execution information
EXECUTION_LOG_FILE="$SCRIPT_DIR/SSLer_execution.log"

# First run file to store domain and email
FIRST_RUN_FILE="$SCRIPT_DIR/SSLer_first_run.txt"

# Function to display valid dates of the certificate in the Unifi Core directory
display_core_cert_info() {
    
    echo -e "${GREEN}------------------------------------${NC}"
    echo -e "${YELLOW}Certificate Information (Unifi Core):${NC}"
    echo -e "${GREEN}------------------------------------${NC}"
    if [ -f "$UNIFI_CORE_CERT_PATH" ]; then
        echo -e "${YELLOW}[ Data Read Date ]: ${GREEN} $(date) ${NC}"
        echo -e "${PURPLE}FQDN entered by user:${CYAN} $domain${NC}"
        echo -e "${YELLOW}Common Name (CN) in certificate:${NC}"
        cert_cn=$(openssl x509 -in $UNIFI_CORE_CERT_PATH -noout -subject | awk -F '=' '{print $NF}' | sed 's/ //g')
        echo -e "${CYAN}$cert_cn${NC}"
        echo -e "${YELLOW}Fingerprint:${NC}"
        echo -e "${PURPLE}$(openssl x509 -in $UNIFI_CORE_CERT_PATH -noout -fingerprint | sed 's/SHA1 Fingerprint=//g')${NC}"
        echo -e "${YELLOW}------------------------------------${NC}"
        echo -e "${YELLOW}[ Not Before ]:${NC}"
        not_before=$(openssl x509 -in $UNIFI_CORE_CERT_PATH -noout -startdate | sed 's/notBefore=//g')
        echo "$not_before"
        echo -e "${YELLOW}[ Not After ]:${NC}"
        not_after=$(openssl x509 -in $UNIFI_CORE_CERT_PATH -noout -enddate | sed 's/notAfter=//g')
        echo "$not_after"
        echo -e "${YELLOW}[ Issued to ]:${NC}"
        openssl x509 -in $UNIFI_CORE_CERT_PATH -noout -subject | sed 's/subject=//g'
        echo -e "${YELLOW}[ Issued by ]:${NC}"
        openssl x509 -in $UNIFI_CORE_CERT_PATH -noout -issuer | sed 's/issuer=//g'
        echo -e "${YELLOW}------------------------------------${NC}"
        
        # Check if the extracted CN exactly matches the entered domain
if [[ "$cert_cn" == "unifi.local" ]]; then
    printf "\n\n\n"
    printf "${RED}THIS IS A SNAKE OIL CERTIFICATE. YOU ARE EITHER RUNNING THIS TOOL FOR THE FIRST TIME OR DELIBERATELY USING AN INSECURE CERTIFICATE. REGARDLESS, PLEASE CONFIRM WHETHER EITHER OF THESE SCENARIOS IS TRUE.${NC}\n\n"
    printf "${CYAN}TYPE 'YES' IN ALL CAPS TO CONTINUE:${NC} "
    read -r confirmation
    if [[ "$confirmation" == "YES" ]]; then
        printf "${GREEN}Continuing as per user confirmation.${NC}\n"
    else
        printf "${RED}Verification: Certificate is a snakeoil certificate.${NC}\n"
        exit 1
    fi
fi





        # Compare certificate expiration date with current date
        current_date=$(date +%s)
        not_after_date=$(date -d "$not_after" +%s)
        if [[ "$current_date" -gt "$not_after_date" ]]; then
            echo -e "${RED}Verification: Certificate has expired.${NC}"
        else
            echo -e "${GREEN}Verification: Certificate is valid until $not_after.${NC}"
        fi
    else
        echo -e "${RED}Error: Unifi Core certificate not found at $UNIFI_CORE_CERT_PATH.${NC}"
        echo -e "${RED}Verification failed: Unifi Core certificate not found.${NC}"
        exit 1
    fi
}

# Function to display valid dates of the downloaded Let's Encrypt certificate
display_letsencrypt_cert_info() {
    echo -e "${GREEN}------------------------------------${NC}"
    echo -e "${YELLOW}Certificate Information (Let's Encrypt):${NC}"
    echo -e "${GREEN}------------------------------------${NC}"
    if [ -f /etc/letsencrypt/live/$domain/cert.pem ]; then
        echo -e "${YELLOW}[ Data Read Date ]: ${GREEN} $(date) ${NC}"
        echo -e "${PURPLE}FQDN entered by user:${CYAN} $domain${NC}"
        echo -e "${YELLOW}Common Name (CN) in certificate:${NC}"
        cert_cn=$(openssl x509 -in /etc/letsencrypt/live/$domain/cert.pem -noout -subject | awk -F '=' '{print $NF}' | sed 's/ //g')
        echo -e "${CYAN}$cert_cn${NC}"
        echo -e "${YELLOW}Fingerprint:${NC}"
        echo -e "${PURPLE}$(openssl x509 -in /etc/letsencrypt/live/$domain/cert.pem -noout -fingerprint | sed 's/SHA1 Fingerprint=//g')${NC}"
        echo -e "${YELLOW}------------------------------------${NC}"
        echo -e "${YELLOW}[ Not Before ]:${NC}"
        not_before=$(openssl x509 -in /etc/letsencrypt/live/$domain/cert.pem -noout -startdate | sed 's/notBefore=//g')
        echo "$not_before"
        echo -e "${YELLOW}[ Not After ]:${NC}"
        not_after=$(openssl x509 -in /etc/letsencrypt/live/$domain/cert.pem -noout -enddate | sed 's/notAfter=//g')
        echo "$not_after"
        echo -e "${YELLOW}[ Issued to ]:${NC}"
        openssl x509 -in /etc/letsencrypt/live/$domain/cert.pem -noout -subject | sed 's/subject=//g'
        echo -e "${YELLOW}[ Issued by ]:${NC}"
        openssl x509 -in /etc/letsencrypt/live/$domain/cert.pem -noout -issuer | sed 's/issuer=//g'
        echo -e "${YELLOW}------------------------------------${NC}"
        
        # Check if the extracted CN exactly matches the entered domain
        if [[ "$cert_cn" == "$domain" ]]; then
            echo -e "${GREEN}Verification: CN matches the entered FQDN.${NC}"
        else
            echo -e "${RED}Verification: Issued to does not match the entered FQDN.${NC}"
            exit 1
        fi

        # Compare certificate expiration date with current date
        current_date=$(date +%s)
        not_after_date=$(date -d "$not_after" +%s)
        if [[ "$current_date" -gt "$not_after_date" ]]; then
            echo -e "${RED}Verification: Certificate has expired.${NC}"
        else
            echo -e "${GREEN}Verification: Certificate is valid until $not_after.${NC}"
        fi
    else
        echo -e "${RED}Verification failed: Let's Encrypt certificate not found.${NC}"
        exit 1
    fi
}

# Function to prompt user for domain and email
dn_and_email() {
    local correct=false
    while [[ $correct == false ]]; do
        read -p "Enter the FQDN desired: " domain
        read -p "Enter the email address for Let's Encrypt certificate: " user_email
        read -p "Enter the FQDN again: " domain_confirm
        read -p "Enter the email address again: " email_confirm
        if [[ "$domain" != "$domain_confirm" ]] || [[ "$user_email" != "$email_confirm" ]]; then
            for (( i=0; i<5; i++ )); do
                echo -e "\033[5m${RED}DOMAIN OR EMAIL VERIFICATION FAILED. ENTRIES DO NOT MATCH. PLEASE TRY AGAIN.${NC}"
                sleep 0.5
                echo -e "\033[0m"
                sleep 0.5
            done
        else
            correct=true
            echo "$domain:$user_email" > "$FIRST_RUN_FILE"
        fi
    done
}

# Check if it's the first run and prompt the user for the domain name and email if so
if [[ ! -f "$FIRST_RUN_FILE" ]]; then
    echo -e "${YELLOW}This appears to be the first run.${NC}"
    dn_and_email
else
    domain=$(cut -d':' -f1 "$FIRST_RUN_FILE")
    user_email=$(cut -d':' -f2 "$FIRST_RUN_FILE")
fi

# Ensure certbot is installed
if ! command -v certbot &>/dev/null; then
    echo "Certbot is not installed. Installing..."
    sudo apt-get update
    sudo apt-get install certbot -y
fi

# Display certificate information and log it
display_core_cert_info | tee -a "$EXECUTION_LOG_FILE"

# Stop the Unifi service
sudo systemctl stop unifi

# Obtain the certificate using Certbot
sudo certbot certonly --manual --preferred-challenges dns -d $domain --agree-tos --email $user_email

# Display downloaded certificate information and log it
display_letsencrypt_cert_info | tee -a "$EXECUTION_LOG_FILE"

# Ask the user if they want to replace the current certificates with the newly downloaded ones
read -p "Do you want to replace the existing certificates with the newly downloaded ones? (yes/no):" replace_certs
if [ "$replace_certs" == "yes" ]; then
    echo -e "${GREEN}User has chosen to replace the existing certificates with the newly downloaded ones.${NC}"
    
    # Backup the existing certificate and key files
    echo -e "${YELLOW}Creating a backup of the existing certificate and key files...${NC}"
    current_date=$(date +"%Y%m%d%H%M%S")
    sudo cp "$UNIFI_CORE_CERT_PATH" "$UNIFI_CORE_PATH/unifi-core_${current_date}.crt.old"
    sudo cp "$UNIFI_CORE_KEY_PATH" "$UNIFI_CORE_PATH/unifi-core_${current_date}.key.old"
    
    # Verify that backup files are created
    if [ -f "$UNIFI_CORE_PATH/unifi-core_${current_date}.crt.old" ] && [ -f "$UNIFI_CORE_PATH/unifi-core_${current_date}.key.old" ]; then
        echo -e "${GREEN}Backup of existing certificate and key files created successfully.${NC}"
        echo -e "${YELLOW}Backup files created:${NC}"
        echo -e "${YELLOW}  - ${UNIFI_CORE_PATH}/unifi-core_${current_date}.crt.old${NC}"
        echo -e "${YELLOW}  - ${UNIFI_CORE_PATH}/unifi-core_${current_date}.key.old${NC}"
    else
        echo -e "${RED}Error: Failed to create a backup of existing certificate and key files.${NC}"
        exit 1
    fi
    
    # Replace the existing certificates with the newly downloaded ones
    echo -e "${YELLOW}Replacing the existing certificates with the newly downloaded ones...${NC}"
    sudo cp "/etc/letsencrypt/live/$domain/fullchain.pem" "$UNIFI_CORE_PATH/unifi-core.crt"
    sudo cp "/etc/letsencrypt/live/$domain/privkey.pem" "$UNIFI_CORE_PATH/unifi-core.key"

    # Verify that certificates are replaced
    if [ -f "$UNIFI_CORE_PATH/unifi-core.crt" ] && [ -f "$UNIFI_CORE_PATH/unifi-core.key" ]; then
        echo -e "${GREEN}Certificates have been successfully replaced.${NC}"
    else
        echo -e "${RED}Error: Failed to replace the existing certificates with the newly downloaded ones.${NC}"
        exit 1
    fi
fi


# Restart the Unifi service to apply the changes
echo "Restarting the Unifi service to apply the changes..."
sudo systemctl start unifi
echo "Unifi service has been restarted."
echo -e "${GREEN}------------------------------------${NC}"
echo -e "${YELLOW}Operation Completed Successfully:${NC}"
echo -e "${GREEN}------------------------------------${NC}"
echo -e "${CYAN}Your certificates have been successfully renewed and/or updated.${NC}"
echo -e "${CYAN}Thank you for using Unifi Device SSLer!${NC}"
# Iterate over each character in the MOTD, colorize and display it
for ((i = 0; i < ${#MOTD}; i++)); do
    color=$(random_color)
    echo -ne "${color}${MOTD:$i:1}${NC}"
done
echo ""  # Add this line to ensure the loop is properly closed
echo ""

About Author