Document toolboxDocument toolbox

dod_crl.sh script

  1. Create the dod-crl  script, enter:

    vi /usr/local/sbin/dod-crl.sh



  2. Add the following contents:

    #!/usr/bin/env bash # CRL Downloader script for manually downloading # CRL .zip bundle from CRL server to support # offline CRL validation. # # Last updated 04 FEB 2023 # # Declare Variables SCRIPT="$(readlink -f "$0")" LOCALREPO_DODLOCAL_CRL_URL="http://crl.dod.local/CertEnroll/ALLCRLZIP.zip" LOCALREPO_DODJITC_CRL_URL="http://crl.dod.local/CertEnroll/JITCALLCRLZIP.zip" DODJITC_CRL_URL="https://crl.nit.disa.mil/getcrlzip?ALL+CRL+ZIP" DODPROD_CRL_URL="https://crl.gds.disa.mil/getcrlzip?ALL+CRL+ZIP" ALLCRLURL="http://crl.dod.local/CertEnroll/ALLCRLZIP.zip" default_crldir="/etc/pki/tls/crl/" # Script Validation: Ensure this script is run as root if [[ "$(whoami)" != "root" ]]; then     logger "$0 ERROR: script must be run as root."     echo "$0 ERROR: script must be run as root." >&2     exit 77 fi validate_required_commands() {     type -P c_rehash >/dev/null 2>&1 || {         logger "$0 ERROR: Required dependency c_rehash is not installed.";         echo "$0 ERROR: Required dependency c_rehash is not installed." >&2;         exit 72;     }     type -P curl >/dev/null 2>&1 || {         logger "$0 ERROR: Required dependency curl is not installed.";         echo "$0 ERROR: Required dependency curl is not installed." >&2;         exit 72;     }     type -P unzip >/dev/null 2>&1 || {         logger "$0 ERROR: Required dependency unzip is not installed.";         echo "$0 ERROR: Required dependency unzip is not installed." >&2;         exit 72;     } } # End validate_required_commands() override_dir_format_ck() {     if [[ -n "${override_crldir}" ]];then         if [[ "${override_crldir}" =~ ^(/)+([a-zA-Z0-9]*/)+$ ]];then             effective_crldir="${override_crldir}"         else             logger "$0 ERROR: --override_crldir ${override_crldir} incorrect directory format."             echo "$0 ERROR: --override_crldir ${override_crldir} incorrect directory format." >&2             exit 64         fi     else         effective_crldir="${default_crldir}"     fi } # End override_dir_format_ck() dir_setup() { # Check input parameter for valid crldir or default     if [[ ! -d "${effective_crldir}" ]];then         mkdir -m 755 -p ${effective_crldir} || {             logger "$0 ERROR: Could not create CRL directory at ${effective_crldir}.";             echo "$0 ERROR: Could not create CRL directory at ${effective_crldir}." >&2; exit 74;         } && {             logger "$0 INFO: ${effective_crldir} did not exist and has been created.";             echo "$0 INFO: ${effective_crldir} did not exist and has been created." >&2;         }     fi } # End dir_setup() staging_area() { # Set up a clean staging area to process CRL ZIP # Remove existing /tmp/.crl_staging so we start clean     if [[ -d /tmp/.crl_staging ]];then         rm -rf /tmp/.crl_staging || {         logger "$0 ERROR: Could not remove existing staging area at /tmp/.crl_staging.";         echo "$0 ERROR: Could not remove existing staging area at /tmp/.crl_staging." >&2;         exit 74;     }     fi     mkdir -m 755 -p /tmp/.crl_staging || {         logger "$0 ERROR: Could not create staging area at /tmp/.crl_staging.";         echo "$0 ERROR: Could not create staging area at /tmp/.crl_staging." >&2;         exit 74;     } } # End staging_area() fetch_crls_from_repo() { crlerrorqty=0 # Loop through each CRL source and perform fetch and extract process if source was requested     for CRL_SOURCE in LOCALREPO_DODLOCAL_CRL LOCALREPO_DODJITC_CRL DODJITC_CRL DODPROD_CRL;do         unset CRL_SOURCE_URL         while [[ "${!CRL_SOURCE}" = true ]];do             CRL_SOURCE_URL=${CRL_SOURCE}_URL             curl "${!CRL_SOURCE_URL}" -o /tmp/.crl_staging/"${CRL_SOURCE}".zip || {                 logger "$0 ERROR: Could not download ${CRL_SOURCE} from ${!CRL_SOURCE_URL}.";                 echo "$0 ERROR: Could not download ${CRL_SOURCE} from ${!CRL_SOURCE_URL}." >&2;                 ((crlerrorqty++))                 break             }             if [[ -f /tmp/.crl_staging/"${CRL_SOURCE}".zip ]];then                 unzip -o /tmp/.crl_staging/"${CRL_SOURCE}".zip -d /tmp/.crl_staging/ || {                     logger "$0 ERROR: Could not extract /tmp/.crl_staging/${CRL_SOURCE}.zip.";                     echo "$0 ERROR: Could not extract /tmp/.crl_staging/${CRL_SOURCE}.zip." >&2;                     ((crlerrorqty++))                     break                 }             else                 logger "$0 ERROR: Could not find /tmp/.crl_staging/${CRL_SOURCE}.zip for processing.";                 echo "$0 ERROR: Could not find /tmp/.crl_staging/${CRL_SOURCE}.zip for processing." >&2;                 ((crlerrorqty++))                 break             fi             # Workaround for JITC CA naming issue             if [[ "${CRL_SOURCE}" =~ ^(LOCALREPO_DODJITC_CRL|DODJITC_CRL)$ ]];then                 if [[ -f /tmp/.crl_staging/DODJITCSWCA_60.crl ]];then                     /bin/cp -rf /tmp/.crl_staging/DODJITCSWCA_60.crl /tmp/.crl_staging/DODJITCSWCA_60_SSL.crl || {                         logger "$0 ERROR: Could not copy /tmp/.crl_staging/DODJITCSWCA_60.crl to /tmp/.crl_staging/DODJITCSWCA_60_SSL.crl. CRL for this CA may not work.";                         echo "$0 ERROR: Could not copy /tmp/.crl_staging/DODJITCSWCA_60.crl to /tmp/.crl_staging/DODJITCSWCA_60_SSL.crl. CRL for this CA may not work." >&2;                         ((crlerrorqty++))                     }                 fi             fi             break         done     done } # End fetch_crls_from_repo() convert_crl_to_pem_and_rehash() { converterror=0 crldirpermerror=0 # If there are .crl files in the staging directory, convert them from DER to PEM and place them in effective CRL directory # then run c_rehash on the effective CRL directory to create hashed symbolic links to the CRL files     if [[ -n "$(find /tmp/.crl_staging/ -maxdepth 1 -name '*.crl' -print -quit)" ]];then         for dercrl in $(find /tmp/.crl_staging/ -maxdepth 1 -name '*.crl' -printf "%f\n");do             openssl crl -in "/tmp/.crl_staging/${dercrl}" -inform DER -outform PEM -out "${effective_crldir}"/"${dercrl}" || {                 logger "$0 ERROR: Could not convert /tmp/.crl_staging/${dercrl} to PEM.";                 echo "$0 ERROR: Could not convert /tmp/.crl_staging/${dercrl} to PEM." >&2;                 (converterror++)             }         done         chown root:root "${effective_crldir}"/*.crl || {             logger "$0 ERROR: Could not set ownership on ${effective_crldir}/*.crl.";             echo "$0 ERROR: Could not set ownership on ${effective_crldir}/*.crl." >&2;             ((crldirpermerror++));         }         chmod 644 "${effective_crldir}"/*.crl || {             logger "$0 ERROR: Could not set permissions on ${effective_crldir}/*.crl.";             echo "$0 ERROR: Could not set permissions on ${effective_crldir}/*.crl." >&2;             ((crldirpermerror++));         }         c_rehash "${effective_crldir}" || {             logger "$0 ERROR: Could not rehash CRLs in ${effective_crldir}. CRLs may be in an inconsistent state!";             echo "$0 ERROR: Could not rehash CRLs in ${effective_crldir}. CRLs may be in an inconsistent state!" >&2;             staging_area_cleanup             exit 74         }     else         logger "$0 ERROR: No .crl files to process under /tmp/.crl_staging/.";         echo "$0 ERROR: No .crl files to process under /tmp/.crl_staging/." >&2;         staging_area_cleanup         exit 74     fi } # End convert_crl_to_pem_and_rehash() staging_area_cleanup() { # Clean up the staging area before exiting     if [[ "${debug}" = true ]];then         logger "$0 DEBUG: Skipping removal of existing staging area at /tmp/.crl_staging.";         echo "$0 DEBUG: Skipping removal of existing staging area at /tmp/.crl_staging." >&2;     else         if [[ -d /tmp/.crl_staging ]];then             rm -rf /tmp/.crl_staging || {             logger "$0 ERROR: Could not remove existing staging area at /tmp/.crl_staging.";             echo "$0 ERROR: Could not remove existing staging area at /tmp/.crl_staging." >&2;             exit 74;             }         fi     fi } # End staging_area_cleanup() crontab_update() { # Create or replace the crontab entry for this script     # Remove previous entry for this script from crontab     (crontab -l 2>/dev/null | sed -e "\,$SCRIPT,d")| crontab -     # Append new entry for this script to crontab     (crontab -l 2>/dev/null || true; echo "0 */4 * * *     ${SCRIPT} ${SCRIPTARGS} >/dev/null 2>&1") | crontab - } exit_status() { # Evaluate success and abnormal but non-abort exit status counters and exit script     if [[ "${crlerrorqty}" > 0 ]]|| [[ "${converterror}" > 0 ]]|| [[ "${crldirpermerror}" > 0 ]];then         logger "$0 ERROR: Script completed, but failed to update all requested CRLs."         echo "$0 ERROR: Script completed, but failed to update all requested CRLs." >&2         exit 75     else         logger "$0 INFO: Script completed. All requested CRLs updated successfully."         echo "$0 INFO: Script completed. All requested CRLs updated successfully." >&2         exit 0     fi } # End exit_status() print_usage() {     echo "Usage for $0:" echo "Usage: $0 [OPTION] [REPOSITORY]" echo "Update local CRL cache from web repository, either manually or via crontab schedule." echo "Example 1, update CRLs to include internal and DoD JITC CRLs from local repository: $0 -uc -lri -lrdj" echo "Example 2, update cron schedule to include internal and DoD JITC CRLs from local repository: $0 -us -lri -lrdj" echo "" echo "Mode arguments, must specify only one mode." echo "  -uc, --update-cache     update local CRL cache from one or more repositories" echo "  -us, --update-schedule  update crontab schedule to run this script automatically for one or more repositories" echo "Repository arguments, must specify one or more repository arguments." echo "  -lri, --local-repo-internal include the local repository for the internal CA CRLs" echo "  -lrdj, --local-repo-dodjitc include the local repository for the DoD JITC CA CRLs" echo "  -dj, --dodjitc      include the DISA repository for the DoD JITC CA CRLs" echo "  -dp, --dodprod      include the DISA repository for the DoD production CA CRLs" echo "Optional arguments. May specify optional override path for CRLs. The default should be sufficient for most use cases." echo "  -o, --output [/target/dir/] override the default /etc/pki/tls/crl/ path with an alternative path. must include trailing /" echo "  -d, --debug         retain /tmp/.crl_staging on exit to support troubleshooting" echo "  -h, --help          print this help menu" echo "" echo "Exit status:" echo " 0  if OK," echo " 64 if syntax error," echo " 72 if missing required dependencies," echo " 74 if error performing file/directory tasks," echo " 75 if error processing one or more requested CRL," echo " 77 if script not run as root." } # End print_usage() # Script execution options debug=false uc=false us=false LOCALREPO_DODLOCAL_CRL=false LOCALREPO_DODJITC_CRL=false DODJITC_CRL=false DODPROD_CRL=false SCRIPTARGS=$(echo $@ | sed -e 's/-us//g' -e 's/--update-schedule//g' -e 's/ $//g'  -e 's/^ //g' -e 's/  -/ -/g' -e 's/^/-uc /g') while [[ $# -gt 0 ]]&& [[ ."$1" =~ .([-]){0,1}+([a-z]) ]]; do     opt="$1";     shift;     case "$opt" in         "-"|"--" )             break 2         ;;         "-uc"|"--update-cache" )             uc=true         ;;         "-us"|"--update-" )             us=true         ;;         "-lri"|"--local-repo-internal" )             LOCALREPO_DODLOCAL_CRL=true         ;;         "-lrdj"|"--local-repo-dodjitc" )             LOCALREPO_DODJITC_CRL=true         ;;         "-dj"|"--dodjitc" )             DODJITC_CRL=true         ;;         "-dp"|"--dodprod" )             DODPROD_CRL=true         ;;         "-o"|"--output" )             override_crldir="$1"             shift         ;;         "-d"|"--debug" )             debug=true         ;;         "-h"|"--help" )             print_usage             exit 0         ;;         *)             echo >&2 "Invalid option: $opt $1"             print_usage             exit 1         ;;    esac done if [[ "${uc}" = false ]]&& [[ "${us}" = false ]];then     logger "$0 ERROR: No modes specified, expected a single mode."     echo "$0 ERROR: No modes specified, expected a single mode." >&2     print_usage     exit 64 fi if [[ "${uc}" = true ]]&& [[ "${us}" = true ]];then     logger "$0 ERROR: Multiple modes specified, expected a single mode."     echo "$0 ERROR: Multiple modes specified, expected a single mode." >&2     print_usage     exit 64 fi if [[ "${uc}" = true ]]&& [[ "${us}" = false ]];then     mode="update-cache" fi if [[ "${us}" = true ]]&& [[ "${uc}" = false ]];then     mode="update-schedule" fi if [[ "${LOCALREPO_DODLOCAL_CRL}" = false ]]&& [[ "${LOCALREPO_DODJITC_CRL}" = false ]]&& [[ "${DODJITC_CRL}" = false ]]&& [[ "${DODPROD_CRL}" = false ]];then     logger "$0 ERROR: No repository specified, expected one or more repositories."     echo "$0 ERROR: No repositories specified, expected one or more repositories." >&2     print_usage     exit 64 fi validate_required_commands if [[ "${mode}" = "update-cache" ]];then     override_dir_format_ck     dir_setup     staging_area     fetch_crls_from_repo     convert_crl_to_pem_and_rehash     staging_area_cleanup     exit_status fi if [[ "${mode}" = "update-schedule" ]];then     override_dir_format_ck     crontab_update fi



  3. Save the file, enter: :wq!

  4. Set the permissions on the dod-crl script, enter:

    chmod 700 /usr/local/sbin/dod-crl.sh



  5. Install the dod-crl script as a cron task, enter:



  6. Note -dp is for DoD Production CRLs. The system must have internet access to https://crl.gds.disa.mil/getcrlzip?ALL+CRL+ZIP

  7. Manually run the dod-crl script for the first time, enter: /usr/local/sbin/dod-crl.sh -uc -dp

Related pages