[2/3] zabbix_agentd: Add helper script to get and verify certificate details

Message ID 20240228191952.28258-3-robin.roevens@disroot.org
State Staged
Commit 670e7d6e363d1a51de623428620b5d50b0e814d8
Headers
Series [1/3] zabbix_agentd: Update to 6.0.27 (LTS) |

Commit Message

Robin Roevens Feb. 28, 2024, 6:58 p.m. UTC
  Add script to parse openssl output on certificates and return it as JSON for consumption by the Zabbix agent.
---
 .../ipfire_certificate_detail.sh              | 91 +++++++++++++++++++
 1 file changed, 91 insertions(+)
 create mode 100755 config/zabbix_agentd/ipfire_certificate_detail.sh
  

Comments

Adolf Belka Feb. 28, 2024, 7:48 p.m. UTC | #1
Reviewed-by: Adolf Belka <adolf.belka@ipfire.org>

On 28/02/2024 19:58, Robin Roevens wrote:
> Add script to parse openssl output on certificates and return it as JSON for consumption by the Zabbix agent.
> ---
>   .../ipfire_certificate_detail.sh              | 91 +++++++++++++++++++
>   1 file changed, 91 insertions(+)
>   create mode 100755 config/zabbix_agentd/ipfire_certificate_detail.sh
>
> diff --git a/config/zabbix_agentd/ipfire_certificate_detail.sh b/config/zabbix_agentd/ipfire_certificate_detail.sh
> new file mode 100755
> index 000000000..9ca0ef5de
> --- /dev/null
> +++ b/config/zabbix_agentd/ipfire_certificate_detail.sh
> @@ -0,0 +1,91 @@
> +#!/bin/bash
> +###############################################################################
> +# ipfire_certificate_detail.sh - Get certificate details and validation results
> +#                                in JSON format for use by Zabbix agent
> +#
> +# Author: robin.roevens (at) disroot.org
> +# Version: 1.0
> +#
> +# Copyright (C) 2007-2024  IPFire Team  <info@ipfire.org>
> +#
> +# This program is free software: you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# 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
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +#
> +###############################################################################
> +
> +# Required binaries
> +OPENSSL=/usr/bin/openssl
> +DATE=/bin/date
> +
> +# Parameter checking
> +[[ $1 ]] || { echo "{\"error\":\"No CA certificate file given.\"}"; exit 1; }
> +[[ -f $1 ]] || { echo "{\"error\":\"CA certificate not found: $1.\"}"; exit 1; }
> +[[ -r $1 ]] || { echo "{\"error\":\"No read permission on CA certificate: $1.\"}"; exit 1; }
> +[[ $2 ]] || { echo "{\"error\":\"No certificate file given.\"}"; exit 1; }
> +[[ -f $2 ]] || { echo "{\"error\":\"Certificate not found: $2.\"}"; exit 1; }
> +[[ -r $2 ]] || { echo "{\"error\":\"No read permission on certificate $2.\"}"; exit 1; }
> +[[ -x $OPENSSL ]] || { echo "{\"error\":\"$OPENSSL binary not found or no permission.\"}"; exit 1; }
> +[[ -x $DATE ]] || { echo "{\"error\":\"$DATE binary not found or no permission.\"}"; exit 1; }
> +
> +cafile=$1
> +cert=$2
> +
> +# Parse certificate details
> +cert_details=$(${OPENSSL} x509 -in "${cert}" -noout -text -certopt no_header,no_sigdump)
> +version=$(echo "${cert_details}" | grep "Version:" | sed 's/^ \+Version: \([0-9]\+\) (.\+)$/\1/g')
> +serial_number=$(echo "${cert_details}" | grep -A1 "Serial Number:" | tr -d '\n' | sed 's/^ \+Serial Number:\(\( \(.*\) ([0-9]\+x[0-9]\+).*\)\|\( \+\(.*\)$\)\)/\3\5/g')
> +signature_algorithm=$(echo "${cert_details}" | grep "Signature Algorithm:" | sed 's/^ \+Signature Algorithm: //g')
> +issuer=$(echo "${cert_details}" | grep "Issuer:" | sed 's/^ \+Issuer: //g' | sed 's/"/\\"/g')
> +not_before_value=$(echo "${cert_details}" | grep "Not Before:" | sed 's/^ \+Not Before: //g')
> +not_before_timestamp=$(${DATE} -d "${not_before_value}" +%s)
> +not_after_value=$(echo "${cert_details}" | grep "Not After :" | sed 's/^ \+Not After : //g')
> +not_after_timestamp=$(${DATE} -d "${not_after_value}" +%s)
> +subject=$(echo "${cert_details}" | grep "Subject:" | sed 's/^ \+Subject: //g' | sed 's/"/\\"/g')
> +public_key_algorithm=$(echo "${cert_details}" | grep "Public Key Algorithm:" | sed 's/^ \+Public Key Algorithm: //g')
> +
> +# Verify certificate
> +cert_verify=$(${OPENSSL} verify -CAfile "${cafile}" "${cert}" 2>&1)
> +if [[ $? != 0 ]]; then
> +	result_value="invalid"
> +	result_message="failed to verify certificate: x509: $(echo "${cert_verify}" | grep -E "error [0-9]+" | sed 's/^.\+: \(.\+\)/\1/g')"
> +else
> +	result_value="valid"
> +	result_message="certificate verified successfully"
> +fi
> +
> +# Generate fingerprints
> +sha1_fingerprint=$(${OPENSSL} x509 -in "${cert}" -noout -fingerprint -sha1 | cut -d= -f2)
> +sha256_fingerprint=$(${OPENSSL} x509 -in "${cert}" -noout -fingerprint -sha256 | cut -d= -f2)
> +
> +# Print certificate details in JSON
> +echo -n "{\"x509\":{"
> +echo -n "\"version\":\"${version}\","
> +echo -n "\"serial_number\":\"${serial_number}\","
> +echo -n "\"signature_algorithm\":\"${signature_algorithm}\","
> +echo -n "\"issuer\":\"${issuer}\","
> +echo -n "\"not_before\":{"
> +echo -n "\"value\":\"${not_before_value}\","
> +echo -n "\"timestamp\":\"${not_before_timestamp}\"},"
> +echo -n "\"not_after\":{"
> +echo -n "\"value\":\"${not_after_value}\","
> +echo -n "\"timestamp\":\"${not_after_timestamp}\"},"
> +echo -n "\"subject\":\"${subject}\","
> +echo -n "\"public_key_algorithm\":\"${public_key_algorithm}\"},"
> +echo -n "\"result\":{"
> +echo -n "\"value\":\"${result_value}\","
> +echo -n "\"message\":\"${result_message}\"},"
> +echo -n "\"sha1_fingerprint\":\"${sha1_fingerprint}\","
> +echo -n "\"sha256_fingerprint\":\"${sha256_fingerprint}\""
> +echo -n "}"
> +
> +exit 0
> \ No newline at end of file
  

Patch

diff --git a/config/zabbix_agentd/ipfire_certificate_detail.sh b/config/zabbix_agentd/ipfire_certificate_detail.sh
new file mode 100755
index 000000000..9ca0ef5de
--- /dev/null
+++ b/config/zabbix_agentd/ipfire_certificate_detail.sh
@@ -0,0 +1,91 @@ 
+#!/bin/bash
+###############################################################################
+# ipfire_certificate_detail.sh - Get certificate details and validation results
+#                                in JSON format for use by Zabbix agent
+#
+# Author: robin.roevens (at) disroot.org
+# Version: 1.0
+#
+# Copyright (C) 2007-2024  IPFire Team  <info@ipfire.org> 
+# 
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# 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
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License 
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+# 
+###############################################################################
+
+# Required binaries
+OPENSSL=/usr/bin/openssl
+DATE=/bin/date
+
+# Parameter checking
+[[ $1 ]] || { echo "{\"error\":\"No CA certificate file given.\"}"; exit 1; }
+[[ -f $1 ]] || { echo "{\"error\":\"CA certificate not found: $1.\"}"; exit 1; }
+[[ -r $1 ]] || { echo "{\"error\":\"No read permission on CA certificate: $1.\"}"; exit 1; }
+[[ $2 ]] || { echo "{\"error\":\"No certificate file given.\"}"; exit 1; }
+[[ -f $2 ]] || { echo "{\"error\":\"Certificate not found: $2.\"}"; exit 1; }
+[[ -r $2 ]] || { echo "{\"error\":\"No read permission on certificate $2.\"}"; exit 1; }
+[[ -x $OPENSSL ]] || { echo "{\"error\":\"$OPENSSL binary not found or no permission.\"}"; exit 1; }
+[[ -x $DATE ]] || { echo "{\"error\":\"$DATE binary not found or no permission.\"}"; exit 1; }
+
+cafile=$1
+cert=$2
+
+# Parse certificate details
+cert_details=$(${OPENSSL} x509 -in "${cert}" -noout -text -certopt no_header,no_sigdump)
+version=$(echo "${cert_details}" | grep "Version:" | sed 's/^ \+Version: \([0-9]\+\) (.\+)$/\1/g')
+serial_number=$(echo "${cert_details}" | grep -A1 "Serial Number:" | tr -d '\n' | sed 's/^ \+Serial Number:\(\( \(.*\) ([0-9]\+x[0-9]\+).*\)\|\( \+\(.*\)$\)\)/\3\5/g')
+signature_algorithm=$(echo "${cert_details}" | grep "Signature Algorithm:" | sed 's/^ \+Signature Algorithm: //g')
+issuer=$(echo "${cert_details}" | grep "Issuer:" | sed 's/^ \+Issuer: //g' | sed 's/"/\\"/g')
+not_before_value=$(echo "${cert_details}" | grep "Not Before:" | sed 's/^ \+Not Before: //g')
+not_before_timestamp=$(${DATE} -d "${not_before_value}" +%s)
+not_after_value=$(echo "${cert_details}" | grep "Not After :" | sed 's/^ \+Not After : //g')
+not_after_timestamp=$(${DATE} -d "${not_after_value}" +%s)
+subject=$(echo "${cert_details}" | grep "Subject:" | sed 's/^ \+Subject: //g' | sed 's/"/\\"/g')
+public_key_algorithm=$(echo "${cert_details}" | grep "Public Key Algorithm:" | sed 's/^ \+Public Key Algorithm: //g')
+
+# Verify certificate
+cert_verify=$(${OPENSSL} verify -CAfile "${cafile}" "${cert}" 2>&1)
+if [[ $? != 0 ]]; then
+	result_value="invalid"
+	result_message="failed to verify certificate: x509: $(echo "${cert_verify}" | grep -E "error [0-9]+" | sed 's/^.\+: \(.\+\)/\1/g')"
+else
+	result_value="valid"
+	result_message="certificate verified successfully"
+fi
+
+# Generate fingerprints
+sha1_fingerprint=$(${OPENSSL} x509 -in "${cert}" -noout -fingerprint -sha1 | cut -d= -f2)
+sha256_fingerprint=$(${OPENSSL} x509 -in "${cert}" -noout -fingerprint -sha256 | cut -d= -f2)
+
+# Print certificate details in JSON
+echo -n "{\"x509\":{"
+echo -n "\"version\":\"${version}\","
+echo -n "\"serial_number\":\"${serial_number}\","
+echo -n "\"signature_algorithm\":\"${signature_algorithm}\","
+echo -n "\"issuer\":\"${issuer}\","
+echo -n "\"not_before\":{"
+echo -n "\"value\":\"${not_before_value}\","
+echo -n "\"timestamp\":\"${not_before_timestamp}\"},"
+echo -n "\"not_after\":{"
+echo -n "\"value\":\"${not_after_value}\","
+echo -n "\"timestamp\":\"${not_after_timestamp}\"},"
+echo -n "\"subject\":\"${subject}\","
+echo -n "\"public_key_algorithm\":\"${public_key_algorithm}\"},"
+echo -n "\"result\":{"
+echo -n "\"value\":\"${result_value}\","
+echo -n "\"message\":\"${result_message}\"},"
+echo -n "\"sha1_fingerprint\":\"${sha1_fingerprint}\","
+echo -n "\"sha256_fingerprint\":\"${sha256_fingerprint}\""
+echo -n "}"
+
+exit 0
\ No newline at end of file