Skip to content
Snippets Groups Projects
freedombone-pin-cert 4.19 KiB
Newer Older
Bob Mottram's avatar
Bob Mottram committed
#!/bin/bash
Bob Mottram's avatar
Bob Mottram committed
#  _____               _           _
# |   __|___ ___ ___ _| |___ _____| |_ ___ ___ ___
# |   __|  _| -_| -_| . | . |     | . | . |   | -_|
# |__|  |_| |___|___|___|___|_|_|_|___|___|_|_|___|
Bob Mottram's avatar
Bob Mottram committed
#
Bob Mottram's avatar
Bob Mottram committed
#                              Freedom in the Cloud
Bob Mottram's avatar
Bob Mottram committed
#
# Performs certificate pinning (HPKP) on a given domain name

# License
# =======
#
Bob Mottram's avatar
Bob Mottram committed
# Copyright (C) 2015-2019 Bob Mottram <bob@freedombone.net>
Bob Mottram's avatar
Bob Mottram committed
#
# This program is free software: you can redistribute it and/or modify
Bob Mottram's avatar
Bob Mottram committed
# it under the terms of the GNU Affero General Public License as published by
Bob Mottram's avatar
Bob Mottram committed
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
Bob Mottram's avatar
Bob Mottram committed
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
Bob Mottram's avatar
Bob Mottram committed
#
Bob Mottram's avatar
Bob Mottram committed
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
Bob Mottram's avatar
Bob Mottram committed

PROJECT_NAME='freedombone'

export TEXTDOMAIN=${PROJECT_NAME}-pin-cert
export TEXTDOMAINDIR="/usr/share/locale"

WEBSITES_DIRECTORY=/etc/nginx/sites-available

Bob Mottram's avatar
Bob Mottram committed
# 90 days
PIN_MAX_AGE=7776000

function pin_all_certs {
    if [ ! -d $WEBSITES_DIRECTORY ]; then
        return
    fi

    cd $WEBSITES_DIRECTORY || exit 24
Bob Mottram's avatar
Bob Mottram committed
    for file in $(dir -d "*") ; do
        if grep -q "Public-Key-Pins" "$file"; then
            DOMAIN_NAME=$file
            KEY_FILENAME=/etc/ssl/private/${DOMAIN_NAME}.key
Bob Mottram's avatar
Bob Mottram committed
            if [ -f "$KEY_FILENAME" ]; then
                BACKUP_KEY_FILENAME=/etc/ssl/certs/${DOMAIN_NAME}.pem
Bob Mottram's avatar
Bob Mottram committed
                if [ -f "$BACKUP_KEY_FILENAME" ]; then
                    KEY_HASH=$(openssl rsa -in "$KEY_FILENAME" -outform der -pubout | openssl dgst -sha256 -binary | openssl enc -base64)
                    BACKUP_KEY_HASH=$(openssl rsa -in "$BACKUP_KEY_FILENAME" -outform der -pubout | openssl dgst -sha256 -binary | openssl enc -base64)
                    if [ ${#BACKUP_KEY_HASH} -gt 5 ]; then

Bob Mottram's avatar
Bob Mottram committed
                        PIN_HEADER="Public-Key-Pins 'pin-sha256=\"${KEY_HASH}\"; pin-sha256=\"${BACKUP_KEY_HASH}\"; max-age=${PIN_MAX_AGE}; includeSubDomains';"
Bob Mottram's avatar
Bob Mottram committed
                        sed -i "s|Public-Key-Pins.*|${PIN_HEADER}|g" "$file"
                        echo $"Pinned $DOMAIN_NAME with keys $KEY_HASH $BACKUP_KEY_HASH"
Bob Mottram's avatar
Bob Mottram committed
if [[ "$1" == "all" ]]; then
    pin_all_certs
    systemctl restart nginx
    exit 0
fi

Bob Mottram's avatar
Bob Mottram committed
DOMAIN_NAME=$1
Bob Mottram's avatar
Bob Mottram committed
KEY_FILENAME=/etc/ssl/private/${DOMAIN_NAME}.key
BACKUP_KEY_FILENAME=/etc/ssl/certs/${DOMAIN_NAME}.pem
SITE_FILENAME=$WEBSITES_DIRECTORY/${DOMAIN_NAME}

Bob Mottram's avatar
Bob Mottram committed
if [ ! "${DOMAIN_NAME}" ]; then
if [ ! -f "$SITE_FILENAME" ]; then
    exit 0
fi
Bob Mottram's avatar
Bob Mottram committed

if [[ $REMOVE == "remove" ]]; then
Bob Mottram's avatar
Bob Mottram committed
    if grep -q "Public-Key-Pins" "$SITE_FILENAME"; then
        sed -i "/Public-Key-Pins/d" "$SITE_FILENAME"
        echo $"Removed pinning for ${DOMAIN_NAME}"
        systemctl restart nginx
    fi
    exit 0
fi

Bob Mottram's avatar
Bob Mottram committed
if [ ! -f "$KEY_FILENAME" ]; then
    echo $"No private key certificate found for $DOMAIN_NAME"
    exit 1
fi

if [ ! -f "$BACKUP_KEY_FILENAME" ]; then
    echo $"No fullchain certificate found for $DOMAIN_NAME"
Bob Mottram's avatar
Bob Mottram committed
fi

Bob Mottram's avatar
Bob Mottram committed
KEY_HASH=$(openssl rsa -in "$KEY_FILENAME" -outform der -pubout | openssl dgst -sha256 -binary | openssl enc -base64)
BACKUP_KEY_HASH=$(openssl rsa -in "$BACKUP_KEY_FILENAME" -outform der -pubout | openssl dgst -sha256 -binary | openssl enc -base64)
Bob Mottram's avatar
Bob Mottram committed

if [ ${#KEY_HASH} -lt 5 ]; then
    echo 'Pin hash unexpectedly short'
    exit 3
fi

if [ ${#BACKUP_KEY_HASH} -lt 5 ]; then
    echo 'Backup pin hash unexpectedly short'
    exit 4
fi

Bob Mottram's avatar
Bob Mottram committed
PIN_HEADER="Public-Key-Pins 'pin-sha256=\"${KEY_HASH}\"; pin-sha256=\"${BACKUP_KEY_HASH}\"; max-age=5184000; includeSubDomains';"
Bob Mottram's avatar
Bob Mottram committed
if ! grep -q "Public-Key-Pins" "$SITE_FILENAME"; then
    sed -i "/ssl_ciphers.*/a     add_header ${PIN_HEADER}" "$SITE_FILENAME"
Bob Mottram's avatar
Bob Mottram committed
else
Bob Mottram's avatar
Bob Mottram committed
    sed -i "s|Public-Key-Pins.*|${PIN_HEADER}|g" "$SITE_FILENAME"
Bob Mottram's avatar
Bob Mottram committed
fi

systemctl restart nginx

Bob Mottram's avatar
Bob Mottram committed
if ! grep -q "add_header Public-Key-Pins" "$SITE_FILENAME"; then
    echo $'Pinning failed'
fi

Bob Mottram's avatar
Bob Mottram committed
echo "Pinned $DOMAIN_NAME with keys $KEY_HASH $BACKUP_KEY_HASH"
Bob Mottram's avatar
Bob Mottram committed
exit 0