Context
After looking at various methods to add a self-signed, public root certificate (ca.crt
) to (snap) Firefox, I experienced some difficulties.
Other solutions
Firefox does not look at the system root ca's by default.
- However, one answer found a hacky workaround to make it do that anyways.
- Another answer says the certificates first need to be imported by hand.
- And the most recent answer, is from 2021, and suggest using the
policies.json
. That works for the apt version. However, for the snap version, thepolicies.json
file is recognised (and used/imported) by Firefox, but the root ca namedca.crt
is not added to the trusted root certificate authorities of snap Firefox (see "snap Firefox" section below for details).
Question
How can one, reliably, and automatically, using Bash, add a root ca named ca.crt
to a snap Firefox installation?
Current Solution
The current solution adds the root ca to the apt (and snap) Firefox installation using the following script:
#!/bin/bash
# Adds the root ca certificate named ca.crt to the apt or snap installation of Firefox.
add_self_signed_root_cert_to_firefox() {
local policies_filepath
policies_filepath=$(get_firefox_policies_path)
local root_ca_filepath="$UBUNTU_CERTIFICATE_DIR$CA_PUBLIC_CERT_FILENAME"
if [ "$(file_exists "$policies_filepath")" == "FOUND" ]; then
if [ "$(file_contains_string "$root_ca_filepath" "$policies_filepath")" == "NOTFOUND" ]; then
# Create a backup of the existing policies.
sudo rm backups/policies.json
sudo cp "$policies_filepath" backups/policies.json
# Generate content to put in policies.json.
local new_json_content
# shellcheck disable=SC2086
new_json_content=$(jq '.policies.Certificates += {
"Install": ["'$root_ca_filepath'"]
}' $policies_filepath)
# Append the content
echo "$new_json_content" | sudo tee "$policies_filepath" >/dev/null
else
red_msg "Your certificate is already added to Firefox."
exit 6
fi
else
new_json_content="$(create_policies_content_to_add_root_ca "$root_ca_filepath")"
echo "$new_json_content" | sudo tee "$policies_filepath" >/dev/null
fi
# Assert the policy is in the file.
if [ "$(file_contains_string "$root_ca_filepath" "$policies_filepath")" == "NOTFOUND" ]; then
red_msg "Error, policy was not found in file:$policies_filepath" "true"
exit 5
fi
}
has_added_self_signed_root_ca_cert_to_firefox() {
local policies_filepath
policies_filepath=$(get_firefox_policies_path)
local root_ca_filepath="$UBUNTU_CERTIFICATE_DIR$CA_PUBLIC_CERT_FILENAME"
read -p "root_ca_filepath=$root_ca_filepath"
read -p "policies_filepath=$policies_filepath"
# Assert the root project for this run/these services is created.
if [ "$(file_exists "certificates/root/$CA_PUBLIC_CERT_FILENAME")" != "FOUND" ]; then
echo "NOTFOUND"
return 0
fi
if [ "$(file_exists "$UBUNTU_CERTIFICATE_DIR$CA_PUBLIC_CERT_FILENAME")" != "FOUND" ]; then
echo "NOTFOUND"
return 0
fi
# Assert the root ca hash is as expected.
if [[ "$(md5sum_is_identical "$UBUNTU_CERTIFICATE_DIR$CA_PUBLIC_CERT_FILENAME" "certificates/root/$CA_PUBLIC_CERT_FILENAME")" != "FOUND" ]]; then
echo "NOTFOUND"
return 0
fi
if [ "$(file_exists "$policies_filepath")" == "FOUND" ]; then
if [ "$(file_contains_string "$root_ca_filepath" "$policies_filepath")" == "NOTFOUND" ]; then
echo "NOTFOUND"
return 0
elif [ "$(file_contains_string "$root_ca_filepath" "$policies_filepath")" == "FOUND" ]; then
echo "FOUND"
return 0
fi
else
echo "NOTFOUND"
fi
}
assert_has_added_self_signed_root_ca_cert_to_firefox() {
if [[ "$(has_added_self_signed_root_ca_cert_to_firefox)" != "FOUND" ]]; then
echo "Error, root ca certificate was not added to apt Firefox."
exit 6
fi
}
firefox_is_installed() {
if [[ "$(firefox_is_installed_with_apt)" == "FOUND" ]]; then
echo "FOUND"
elif [[ "$(firefox_is_installed_with_snap)" == "FOUND" ]]; then
echo "FOUND"
else
echo "NOTFOUND"
fi
}
firefox_is_installed_with_apt() {
if dpkg -l firefox &>/dev/null; then
echo "FOUND"
else
echo "NOTFOUND"
fi
}
firefox_is_installed_with_snap() {
if snap list | grep -v firefox &>/dev/null; then
echo "FOUND"
else
echo "NOTFOUND"
fi
}
get_firefox_policies_path() {
local policies_filepath
#elif snap list | grep -v firefox &>/dev/null; then
if [ "$(firefox_via_snap)" == "FOUND" ]; then
# policies_filepath="/snap/firefox/current/distribution/policies.json"
sudo mkdir -p "/etc/firefox/policies"
policies_filepath="/etc/firefox/policies/policies.json"
# TODO: prevent False positive on apt package if snap Firefox is installed.
elif [[ "$(apt_package_is_installed "Firefox")" != "FOUND" ]]; then
#if dpkg -l firefox &>/dev/null; then
policies_filepath="/etc/firefox/policies/policies.json"
else
echo "Error, firefox installation was not found."
exit 6
fi
echo "$policies_filepath"
}
create_policies_content_to_add_root_ca() {
local root_ca_filepath="$1"
local inner
inner=$(
jq -n --argjson Install '["'"$root_ca_filepath"'"]' \
'$ARGS.named'
)
local medium
medium=$(
jq -n --argjson Certificates "$inner" \
'$ARGS.named'
)
local final
final=$(
jq -n --argjson policies "$medium" \
'$ARGS.named'
)
echo "$final"
# Desired output (created with jq as exercise, and for modularity):
# {
# "policies": {
# "Certificates": {
# "Install": [
# "/usr/local/share/ca-certificates/ca.crt"
# ]
# }
# }
# }
}
close_restart_close_firefox() {
# Close firefox.
pkill firefox >>/dev/null 2>&1
green_msg "Opening and closing Firefox, please wait 3 seconds." "true"
# TODO: Verify no errors occur when running Firefox.
# TODO: Verify Firefox was started successfully.
nohup firefox >/dev/null 2>&1 &
sleep 3
pkill firefox >>/dev/null 2>&1
green_msg "Proceeding with script." "true"
}
This works for the apt verion of Firefox. However, it does not work for the snap version of Firefox, details are in the next subsection.
Snap Firefox Issue
For the standard installation on Ubuntu (snap Firefox), the content from the /etc/firefox/policies/policies.json
is loaded. However, the certificate is not recognised. The link to the ca.crt
is recognised:
However, it is not listed in the about:preferences
> certificates
:
On the apt version, the certificates are added and shown in that list.
Note
For completeness, I also have a script to swap the snap installation to apt, however, I am looking for a less invasive method that preserves the Firefox settings of the user.