├── .codespell-ignore ├── .codespellrc ├── .editorconfig ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── dependabot.yml └── workflows │ ├── codespell.yml │ ├── integration_tests.yml │ ├── integration_tests_with_proxy.yml │ ├── publish.yml │ ├── unit_tests.yml │ └── unit_tests_with_proxy.yml ├── .gitignore ├── .gitmodules ├── AUTHORS.md ├── CITATION.cff ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── COPYING.md ├── COPYRIGHT.md ├── ChangeLog ├── GNUmakefile ├── INSTALL.md ├── Makefile ├── NEWS.md ├── README.md ├── RELEASE_NOTES.md ├── SECURITY.md ├── VERSION ├── check_ssl_cert ├── check_ssl_cert.1 ├── check_ssl_cert.completion ├── check_ssl_cert.spec ├── check_ssl_cert_icinga2.conf ├── pull_request_template.md ├── test ├── badssl_tests.sh ├── cabundle.crt ├── cacert.crt ├── cacerts.jks ├── cert_with_empty_subject.crt ├── cert_with_subject_without_cn.crt ├── corti.li.pem ├── der.cer ├── derlink.cer ├── fullchain.pem ├── incomplete_chain.pem ├── integration_tests.sh ├── keystore.jks ├── mosquitto.org.crt ├── tinyproxy.conf ├── unit_tests.sh └── wrong_chain.pem ├── utils ├── check_deps.sh ├── check_documentation.sh ├── deprecated.txt ├── help.txt ├── prepare_rpm.sh ├── publish_release.sh ├── start_proxy.sh ├── stats.sh └── update_citation.sh └── varia └── check_ssl_cert_stats.xlsx /.codespell-ignore: -------------------------------------------------------------------------------- 1 | ba 2 | -------------------------------------------------------------------------------- /.codespellrc: -------------------------------------------------------------------------------- 1 | [codespell] 2 | check-filenames = 3 | check-hidden = 4 | skip = ./test/cabundle.crt,.git,check_ssl_cert-* 5 | ignore-words = .codespell-ignore 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | # 4 space indentation 13 | [*] 14 | indent_style = space 15 | indent_size = 4 16 | 17 | # Tab indentation (no size specified) 18 | [Makefile] 19 | indent_style = tab 20 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: matteocorti 4 | liberapay: matteocorti 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | 12 | A clear and concise description of what the bug is. 13 | 14 | **To Reproduce** 15 | 16 | Steps to reproduce the behavior. 17 | 18 | **Expected behavior** 19 | 20 | A clear and concise description of what you expected to happen. 21 | 22 | **System (please complete the following information):** 23 | 24 | - OS: [e.g. iOS] 25 | - OS version: [e.g. 22] 26 | - check_ssl_cert version: [e.g. 1.19.0] 27 | - OpenSSL version (```openssl version```): [e.g., 3.0.0] 28 | 29 | **Additional context/output** 30 | 31 | Add any other context or output (e.g., from `check_ssl_cert -d -v`) about the problem here. 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | 12 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 13 | 14 | **Describe the solution you'd like** 15 | 16 | A clear and concise description of what you want to happen. 17 | 18 | **Describe alternatives you've considered** 19 | 20 | A clear and concise description of any alternative solutions or features you've considered. 21 | 22 | **Additional context** 23 | 24 | Add any other context or screenshots about the feature request here. 25 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | -------------------------------------------------------------------------------- /.github/workflows/codespell.yml: -------------------------------------------------------------------------------- 1 | # GitHub Action to automate the identification of common misspellings in text files. 2 | # https://github.com/codespell-project/actions-codespell 3 | # https://github.com/codespell-project/codespell 4 | name: codespell 5 | on: 6 | push: 7 | paths-ignore: 8 | - varia/** 9 | pull_request: 10 | 11 | jobs: 12 | codespell: 13 | name: Check for spelling errors 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | - uses: codespell-project/actions-codespell@master 18 | -------------------------------------------------------------------------------- /.github/workflows/integration_tests.yml: -------------------------------------------------------------------------------- 1 | name: Integration tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - $default-branch 7 | - development 8 | - master 9 | paths-ignore: 10 | - varia/** 11 | - '**.md' 12 | - utils/prepare_rpm.sh 13 | - .github/workflows/publish.yml 14 | schedule: 15 | # We run the integration tests daily. These tests depend on external hosts and certificates 16 | # and it's useful to know when something is not working as soon as possible 17 | # 18 | # * is a special character in YAML so you have to quote this string 19 | - cron: '42 7 * * *' 20 | # Run tests for any PRs 21 | pull_request: 22 | workflow_dispatch: 23 | 24 | permissions: 25 | contents: read 26 | 27 | jobs: 28 | 29 | ############################################################################## 30 | # macOS 31 | 32 | macos: 33 | name: Running integration tests on ${{ matrix.os }} 34 | strategy: 35 | fail-fast: false 36 | matrix: 37 | os: 38 | - macos-13 39 | - macos-14 40 | - macos-latest 41 | runs-on: ${{ matrix.os }} 42 | steps: 43 | 44 | - name: Git clone repository 45 | uses: actions/checkout@v4 46 | 47 | - name: Install shellcheck 48 | run: brew install shellcheck shunit2 bash-completion nmap 49 | 50 | - name: install cpanm and Date::Parse 51 | uses: perl-actions/install-with-cpanm@stable 52 | with: 53 | install: Date::Parse 54 | 55 | - name: Run the integration tests 56 | run: | 57 | uname -a \ 58 | && make integration_tests \ 59 | && bash -c "source ./check_ssl_cert.completion && complete -p check_ssl_cert" \ 60 | && make dist \ 61 | && sudo make install_bash_completion && bash -c "source ./check_ssl_cert.completion && complete -p check_ssl_cert" \ 62 | && if command -v shellcheck > /dev/null 2>&1 ; then shellcheck ./check_ssl_cert test/*.sh ; fi 63 | 64 | 65 | ############################################################################## 66 | # Linuxes 67 | 68 | linux: 69 | # The host should always be linux 70 | runs-on: ubuntu-latest 71 | name: Running integration tests on ${{ matrix.distro }} 72 | strategy: 73 | fail-fast: false 74 | matrix: 75 | distro: 76 | - 'debian:11' 77 | - 'debian:12' 78 | - 'ubuntu:20.04' 79 | - 'ubuntu:22.04' 80 | - 'alpine:3.13' 81 | - 'fedora:40' 82 | - 'fedora:41' 83 | include: 84 | 85 | 86 | - distro: 'debian:11' 87 | pre: >- 88 | apt-get update && 89 | DEBIAN_FRONTEND=noninteractive apt-get -y install nmap shellcheck curl sudo perl make bzip2 file openssl dnsutils shunit2 man bc bash-completion iproute2 default-jre 90 | - distro: 'debian:12' 91 | pre: >- 92 | apt-get update && 93 | DEBIAN_FRONTEND=noninteractive apt-get -y install nmap shellcheck curl sudo perl make bzip2 file openssl dnsutils shunit2 man bc bash-completion iproute2 default-jre 94 | 95 | - distro: 'ubuntu:20.04' 96 | pre: >- 97 | apt-get update && 98 | DEBIAN_FRONTEND=noninteractive apt-get -y install nmap shellcheck curl sudo perl make bzip2 file openssl dnsutils shunit2 man bc net-tools bash-completion default-jre 99 | - distro: 'ubuntu:22.04' 100 | pre: >- 101 | apt-get update && 102 | DEBIAN_FRONTEND=noninteractive apt-get -y install nmap shellcheck curl sudo perl make bzip2 file openssl dnsutils shunit2 man bc net-tools bash-completion default-jre 103 | 104 | - distro: 'alpine:3.13' 105 | pre: >- 106 | apk update && 107 | apk upgrade && 108 | apk add -U bash && 109 | apk add nmap shellcheck curl sudo perl make wget bzip2 file openssl bind-tools git shunit2 mandoc bc bash-completion openjdk11 110 | 111 | 112 | - distro: 'fedora:40' 113 | pre: >- 114 | dnf upgrade -y && 115 | dnf install -y hostname && 116 | dnf install -y nmap ShellCheck curl sudo perl make bzip2 file openssl bind-utils git shunit2 man bc net-tools bash-completion java-latest-openjdk 117 | - distro: 'fedora:41' 118 | pre: >- 119 | dnf upgrade -y && 120 | dnf install -y hostname && 121 | dnf install -y nmap ShellCheck curl sudo perl make bzip2 file openssl bind-utils git shunit2 man bc net-tools bash-completion java-latest-openjdk 122 | 123 | 124 | steps: 125 | 126 | - name: Git clone repository 127 | uses: actions/checkout@v4 128 | 129 | - name: Run the integration tests on ${{ matrix.distro }} 130 | env: 131 | PRE: ${{ matrix.pre }} 132 | run: | 133 | echo $PRE > ./prep-cmd.sh 134 | docker run --network host -w /check_ssl_cert -v ${PWD}:/check_ssl_cert ${{ matrix.distro }} \ 135 | /bin/sh -c 'sh ./prep-cmd.sh \ 136 | && curl -L https://cpanmin.us | sudo perl - --sudo App::cpanminus \ 137 | && cpanm --sudo install Date::Parse \ 138 | && uname -a \ 139 | && make integration_tests \ 140 | && bash -c "source ./check_ssl_cert.completion && complete -p check_ssl_cert" \ 141 | && make dist \ 142 | && sudo make install_bash_completion && bash -c "source ./check_ssl_cert.completion && complete -p check_ssl_cert" \ 143 | && if command -v shellcheck > /dev/null 2>&1 ; then shellcheck ./check_ssl_cert test/*.sh ; fi' 144 | -------------------------------------------------------------------------------- /.github/workflows/integration_tests_with_proxy.yml: -------------------------------------------------------------------------------- 1 | name: Integration tests with proxy 2 | 3 | on: 4 | push: 5 | branches: 6 | - $default-branch 7 | - development 8 | - master 9 | paths-ignore: 10 | - varia/** 11 | - '**.md' 12 | - utils/prepare_rpm.sh 13 | - .github/workflows/publish.yml 14 | schedule: 15 | # We run the integration tests daily. These tests depend on external hosts and certificates 16 | # and it's useful to know when something is not working as soon as possible 17 | # 18 | # * is a special character in YAML so you have to quote this string 19 | - cron: '42 7 * * *' 20 | # Run tests for any PRs 21 | pull_request: 22 | workflow_dispatch: 23 | 24 | permissions: 25 | contents: read 26 | 27 | jobs: 28 | 29 | ############################################################################## 30 | # macOS 31 | 32 | macos: 33 | name: Running integration tests on ${{ matrix.os }} 34 | strategy: 35 | fail-fast: false 36 | matrix: 37 | os: 38 | - macos-13 39 | - macos-14 40 | - macos-latest 41 | runs-on: ${{ matrix.os }} 42 | steps: 43 | 44 | - name: Git clone repository 45 | uses: actions/checkout@v4 46 | 47 | - name: Install shellcheck 48 | run: brew install shellcheck shunit2 bash-completion nmap tinyproxy 49 | 50 | - name: install cpanm and Date::Parse 51 | uses: perl-actions/install-with-cpanm@stable 52 | with: 53 | install: Date::Parse 54 | 55 | - name: Run the integration tests 56 | run: | 57 | uname -a \ 58 | && make integration_tests \ 59 | && bash -c "source ./check_ssl_cert.completion && complete -p check_ssl_cert" \ 60 | && make dist \ 61 | && sudo make install_bash_completion && bash -c "source ./check_ssl_cert.completion && complete -p check_ssl_cert" \ 62 | && if command -v shellcheck > /dev/null 2>&1 ; then shellcheck ./check_ssl_cert test/*.sh ; fi 63 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish RPM 2 | 3 | on: 4 | workflow_dispatch: 5 | release: 6 | types: [published] 7 | permissions: 8 | contents: read 9 | 10 | jobs: 11 | linux: 12 | # The host should always be linux 13 | runs-on: ubuntu-latest 14 | name: Building RPMs on ${{ matrix.distro }} 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | distro: 19 | - 'fedora:42' 20 | - 'fedora:41' 21 | include: 22 | - distro: 'fedora:42' 23 | pre: >- 24 | dnf install -y hostname && 25 | dnf install -y nmap ShellCheck curl sudo perl make bzip2 file openssl rpm-build openssh-clients bc bash-completion 26 | - distro: 'fedora:41' 27 | pre: >- 28 | dnf install -y hostname && 29 | dnf install -y nmap ShellCheck curl sudo perl make bzip2 file openssl rpm-build openssh-clients bc bash-completion 30 | steps: 31 | - name: Git clone repository 32 | uses: actions/checkout@v4 33 | with: 34 | submodules: true 35 | - name: Build the RPM on ${{ matrix.distro }} 36 | env: 37 | PRE: ${{ matrix.pre }} 38 | SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }} 39 | run: | 40 | echo $PRE > ./prep-cmd.sh 41 | echo "${SSH_PRIVATE_KEY}" > id_rsa 42 | docker run --network host -w /check_ssl_cert -v ${PWD}:/check_ssl_cert ${{ matrix.distro }} \ 43 | /bin/sh -c 'sh ./prep-cmd.sh \ 44 | && uname -a \ 45 | && whoami \ 46 | && pwd \ 47 | && . ./utils/prepare_rpm.sh \ 48 | && echo "$RPM --> $RPMDIR" \ 49 | && echo "$SRPM --> $SRPMDIR" \ 50 | && mkdir -p /root/.ssh \ 51 | && chmod 700 /root/.ssh \ 52 | && cp id_rsa /root/.ssh \ 53 | && chmod 600 /root/.ssh/id_rsa \ 54 | && scp -oStrictHostKeyChecking=no $RPM github@rpm.corti.li:$RPMDIR \ 55 | && scp -oStrictHostKeyChecking=no $SRPM github@rpm.corti.li:$SRPMDIR \ 56 | && echo "Updating /var/www/rpm/$DIST/$RELEASE" \ 57 | && ssh -oStrictHostKeyChecking=no github@rpm.corti.li "createrepo /var/www/rpm/$DIST/$RELEASE" ' 58 | -------------------------------------------------------------------------------- /.github/workflows/unit_tests.yml: -------------------------------------------------------------------------------- 1 | name: Unit tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - $default-branch 7 | - development 8 | - master 9 | paths-ignore: 10 | - varia/** 11 | - '**.md' 12 | - utils/prepare_rpm.sh 13 | - .github/workflows/publish.yml 14 | # Run tests for any PRs 15 | pull_request: 16 | workflow_dispatch: 17 | 18 | permissions: 19 | contents: read 20 | 21 | jobs: 22 | 23 | ############################################################################## 24 | # macOS 25 | 26 | macos: 27 | name: Running unit tests on ${{ matrix.os }} 28 | strategy: 29 | fail-fast: false 30 | matrix: 31 | os: 32 | - macos-13 33 | - macos-14 34 | - macos-latest 35 | runs-on: ${{ matrix.os }} 36 | steps: 37 | 38 | - name: Git clone repository 39 | uses: actions/checkout@v4 40 | 41 | - name: Install shellcheck 42 | run: brew install shellcheck shunit2 bash-completion nmap 43 | 44 | - name: install cpanm and Date::Parse 45 | uses: perl-actions/install-with-cpanm@stable 46 | with: 47 | install: Date::Parse 48 | 49 | - name: Run the unit tests 50 | run: | 51 | uname -a \ 52 | && make unit_tests \ 53 | && bash -c "source ./check_ssl_cert.completion && complete -p check_ssl_cert" \ 54 | && make dist \ 55 | && sudo make install_bash_completion && bash -c "source ./check_ssl_cert.completion && complete -p check_ssl_cert" \ 56 | && if command -v shellcheck > /dev/null 2>&1 ; then shellcheck ./check_ssl_cert test/*.sh ; fi 57 | 58 | 59 | ############################################################################## 60 | # Linuxes 61 | 62 | linux: 63 | # The host should always be linux 64 | runs-on: ubuntu-latest 65 | name: Running unit tests on ${{ matrix.distro }} 66 | strategy: 67 | fail-fast: false 68 | matrix: 69 | distro: 70 | - 'debian:11' 71 | - 'debian:12' 72 | - 'ubuntu:20.04' 73 | - 'ubuntu:22.04' 74 | - 'alpine:3.13' 75 | - 'fedora:40' 76 | - 'fedora:41' 77 | include: 78 | 79 | - distro: 'debian:11' 80 | pre: >- 81 | apt-get update && 82 | DEBIAN_FRONTEND=noninteractive apt-get -y install nmap shellcheck curl sudo perl make bzip2 file openssl dnsutils shunit2 man bc bash-completion iproute2 default-jre 83 | - distro: 'debian:12' 84 | pre: >- 85 | apt-get update && 86 | DEBIAN_FRONTEND=noninteractive apt-get -y install nmap shellcheck curl sudo perl make bzip2 file openssl dnsutils shunit2 man bc bash-completion iproute2 default-jre 87 | 88 | - distro: 'ubuntu:20.04' 89 | pre: >- 90 | apt-get update && 91 | DEBIAN_FRONTEND=noninteractive apt-get -y install nmap shellcheck curl sudo perl make bzip2 file openssl dnsutils shunit2 man bc net-tools bash-completion default-jre 92 | - distro: 'ubuntu:22.04' 93 | pre: >- 94 | apt-get update && 95 | DEBIAN_FRONTEND=noninteractive apt-get -y install nmap shellcheck curl sudo perl make bzip2 file openssl dnsutils shunit2 man bc net-tools bash-completion default-jre 96 | 97 | 98 | - distro: 'alpine:3.13' 99 | pre: >- 100 | apk update && 101 | apk upgrade && 102 | apk add -U bash && 103 | apk add nmap shellcheck curl sudo perl make wget bzip2 file openssl bind-tools git shunit2 mandoc bc bash-completion openjdk11 104 | 105 | 106 | - distro: 'fedora:40' 107 | pre: >- 108 | dnf upgrade -y && 109 | dnf install -y hostname && 110 | dnf install -y nmap ShellCheck curl sudo perl make bzip2 file openssl bind-utils git shunit2 man bc net-tools bash-completion java-latest-openjdk 111 | - distro: 'fedora:41' 112 | pre: >- 113 | dnf upgrade -y && 114 | dnf install -y hostname && 115 | dnf install -y nmap ShellCheck curl sudo perl make bzip2 file openssl bind-utils git shunit2 man bc net-tools bash-completion java-latest-openjdk 116 | 117 | 118 | steps: 119 | 120 | - name: Git clone repository 121 | uses: actions/checkout@v4 122 | 123 | - name: Run the unit tests on ${{ matrix.distro }} 124 | env: 125 | PRE: ${{ matrix.pre }} 126 | run: | 127 | echo $PRE > ./prep-cmd.sh 128 | docker run --network host -w /check_ssl_cert -v ${PWD}:/check_ssl_cert ${{ matrix.distro }} \ 129 | /bin/sh -c 'sh ./prep-cmd.sh \ 130 | && curl -L https://cpanmin.us | sudo perl - --sudo App::cpanminus \ 131 | && cpanm --sudo install Date::Parse \ 132 | && uname -a \ 133 | && make unit_tests \ 134 | && bash -c "source ./check_ssl_cert.completion && complete -p check_ssl_cert" \ 135 | && make dist \ 136 | && sudo make install_bash_completion && bash -c "source ./check_ssl_cert.completion && complete -p check_ssl_cert" \ 137 | && if command -v shellcheck > /dev/null 2>&1 ; then shellcheck ./check_ssl_cert test/*.sh ; fi' 138 | 139 | rpm: 140 | # The host should always be linux 141 | runs-on: ubuntu-latest 142 | name: Running RPM tests on ${{ matrix.distro }} 143 | strategy: 144 | fail-fast: false 145 | matrix: 146 | distro: 147 | - 'fedora:39' 148 | - 'fedora:40' 149 | - 'fedora:41' 150 | include: 151 | - distro: 'fedora:39' 152 | pre: >- 153 | dnf install -y hostname && 154 | dnf install -y nmap ShellCheck curl sudo perl make bzip2 file openssl bind-utils rpm-build git bash-completion 155 | - distro: 'fedora:40' 156 | pre: >- 157 | dnf install -y hostname && 158 | dnf install -y nmap ShellCheck curl sudo perl make bzip2 file openssl bind-utils rpm-build git bash-completion 159 | - distro: 'fedora:41' 160 | pre: >- 161 | dnf install -y hostname && 162 | dnf install -y nmap ShellCheck curl sudo perl make bzip2 file openssl bind-utils rpm-build git bash-completion 163 | steps: 164 | 165 | - name: Git clone repository 166 | uses: actions/checkout@v4 167 | 168 | - name: Build the RPM on ${{ matrix.distro }} 169 | env: 170 | PRE: ${{ matrix.pre }} 171 | run: | 172 | echo $PRE > ./prep-cmd.sh 173 | docker run --network host -w /check_ssl_cert -v ${PWD}:/check_ssl_cert ${{ matrix.distro }} \ 174 | /bin/sh -c 'sh ./prep-cmd.sh \ 175 | && uname -a \ 176 | && make rpm' 177 | 178 | rpm-nocompletion: 179 | # The host should always be linux 180 | runs-on: ubuntu-latest 181 | name: Running RPM tests without bash completion on ${{ matrix.distro }} 182 | strategy: 183 | fail-fast: false 184 | matrix: 185 | distro: 186 | - 'fedora:39' 187 | - 'fedora:40' 188 | - 'fedora:40' 189 | include: 190 | - distro: 'fedora:39' 191 | pre: >- 192 | dnf install -y hostname && 193 | dnf install -y nmap ShellCheck curl sudo perl make bzip2 file openssl bind-utils rpm-build git 194 | - distro: 'fedora:40' 195 | pre: >- 196 | dnf install -y hostname && 197 | dnf install -y nmap ShellCheck curl sudo perl make bzip2 file openssl bind-utils rpm-build git 198 | - distro: 'fedora:41' 199 | pre: >- 200 | dnf install -y hostname && 201 | dnf install -y nmap ShellCheck curl sudo perl make bzip2 file openssl bind-utils rpm-build git 202 | steps: 203 | 204 | - name: Git clone repository 205 | uses: actions/checkout@v4 206 | 207 | - name: Build the RPM on ${{ matrix.distro }} 208 | env: 209 | PRE: ${{ matrix.pre }} 210 | run: | 211 | echo $PRE > ./prep-cmd.sh 212 | docker run --network host -w /check_ssl_cert -v ${PWD}:/check_ssl_cert ${{ matrix.distro }} \ 213 | /bin/sh -c 'sh ./prep-cmd.sh \ 214 | && uname -a \ 215 | && make rpm' 216 | -------------------------------------------------------------------------------- /.github/workflows/unit_tests_with_proxy.yml: -------------------------------------------------------------------------------- 1 | name: Unit tests with proxy 2 | 3 | on: 4 | push: 5 | branches: 6 | - $default-branch 7 | - development 8 | - master 9 | paths-ignore: 10 | - varia/** 11 | - '**.md' 12 | - utils/prepare_rpm.sh 13 | - .github/workflows/publish.yml 14 | # Run tests for any PRs 15 | pull_request: 16 | workflow_dispatch: 17 | 18 | permissions: 19 | contents: read 20 | 21 | jobs: 22 | 23 | ############################################################################## 24 | # macOS 25 | 26 | macos: 27 | name: Running unit tests on ${{ matrix.os }} 28 | strategy: 29 | fail-fast: false 30 | matrix: 31 | os: 32 | - macos-13 33 | - macos-14 34 | - macos-latest 35 | runs-on: ${{ matrix.os }} 36 | steps: 37 | 38 | - name: Git clone repository 39 | uses: actions/checkout@v4 40 | 41 | - name: Install shellcheck 42 | run: brew install shellcheck shunit2 bash-completion nmap tinyproxy 43 | 44 | - name: install cpanm and Date::Parse 45 | uses: perl-actions/install-with-cpanm@stable 46 | with: 47 | install: Date::Parse 48 | 49 | - name: Run the unit tests 50 | run: | 51 | uname -a \ 52 | && make unit_tests_with_proxy \ 53 | && bash -c "source ./check_ssl_cert.completion && complete -p check_ssl_cert" \ 54 | && make dist \ 55 | && sudo make install_bash_completion && bash -c "source ./check_ssl_cert.completion && complete -p check_ssl_cert" \ 56 | && if command -v shellcheck > /dev/null 2>&1 ; then shellcheck ./check_ssl_cert test/*.sh ; fi 57 | 58 | rpm: 59 | # The host should always be linux 60 | runs-on: ubuntu-latest 61 | name: Running RPM tests on ${{ matrix.distro }} 62 | strategy: 63 | fail-fast: false 64 | matrix: 65 | distro: 66 | - 'fedora:40' 67 | - 'fedora:41' 68 | include: 69 | - distro: 'fedora:40' 70 | pre: >- 71 | dnf install -y hostname && 72 | dnf install -y nmap ShellCheck curl sudo perl make bzip2 file openssl bind-utils rpm-build git bash-completion 73 | - distro: 'fedora:41' 74 | pre: >- 75 | dnf install -y hostname && 76 | dnf install -y nmap ShellCheck curl sudo perl make bzip2 file openssl bind-utils rpm-build git bash-completion 77 | steps: 78 | 79 | - name: Git clone repository 80 | uses: actions/checkout@v4 81 | 82 | - name: Build the RPM on ${{ matrix.distro }} 83 | env: 84 | PRE: ${{ matrix.pre }} 85 | run: | 86 | echo $PRE > ./prep-cmd.sh 87 | docker run --network host -w /check_ssl_cert -v ${PWD}:/check_ssl_cert ${{ matrix.distro }} \ 88 | /bin/sh -c 'sh ./prep-cmd.sh \ 89 | && uname -a \ 90 | && make rpm' 91 | 92 | rpm-nocompletion: 93 | # The host should always be linux 94 | runs-on: ubuntu-latest 95 | name: Running RPM tests without bash completion on ${{ matrix.distro }} 96 | strategy: 97 | fail-fast: false 98 | matrix: 99 | distro: 100 | - 'fedora:39' 101 | - 'fedora:40' 102 | - 'fedora:41' 103 | include: 104 | - distro: 'fedora:39' 105 | pre: >- 106 | dnf install -y hostname && 107 | dnf install -y nmap ShellCheck curl sudo perl make bzip2 file openssl bind-utils rpm-build git 108 | - distro: 'fedora:40' 109 | pre: >- 110 | dnf install -y hostname && 111 | dnf install -y nmap ShellCheck curl sudo perl make bzip2 file openssl bind-utils rpm-build git 112 | - distro: 'fedora:41' 113 | pre: >- 114 | dnf install -y hostname && 115 | dnf install -y nmap ShellCheck curl sudo perl make bzip2 file openssl bind-utils rpm-build git 116 | steps: 117 | 118 | - name: Git clone repository 119 | uses: actions/checkout@v4 120 | 121 | - name: Build the RPM on ${{ matrix.distro }} 122 | env: 123 | PRE: ${{ matrix.pre }} 124 | run: | 125 | echo $PRE > ./prep-cmd.sh 126 | docker run --network host -w /check_ssl_cert -v ${PWD}:/check_ssl_cert ${{ matrix.distro }} \ 127 | /bin/sh -c 'sh ./prep-cmd.sh \ 128 | && uname -a \ 129 | && make rpm' 130 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | check_ssl_cert-** 2 | **~ 3 | **.crt 4 | **.bak 5 | **.error 6 | \#** 7 | .#** 8 | .DS_Store 9 | headers.txt 10 | varia/~$check_ssl_cert_stats.xlsx 11 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matteocorti/check_ssl_cert/af6633dd450f14c1c725cff3ca12130d73a46e15/.gitmodules -------------------------------------------------------------------------------- /AUTHORS.md: -------------------------------------------------------------------------------- 1 | # check\_ssl\_cert list of authors 2 | 3 | Maintainer: [Matteo Corti](https://github.com/matteocorti) <[matteo@corti.li](mailto:matteo@.corti.li)> 4 | 5 | * Many thanks to Kenny McCormack for his help on comp.unix.shell on how to implement a timeout 6 | * Many thanks to Dan Wallis for several patches and fixes (see the [Changelog](Changelog)) 7 | * Many thanks to Tuomas Haarala for the ```-P``` option patch to check TLS certs using other protocols 8 | * Many thanks to Marcus Rejås for the ```-N``` and ```-n``` patches 9 | * Many thanks to Marc Fournier for 10 | * the ```==``` bashism fix and 11 | * the ```mktemp``` error handling patch 12 | * Many thanks to Wolfgang Schricker for 13 | * the selfsigned bug report and cleanup fixes and 14 | * the patch adding the possibility to check local files (```-``` option) 15 | * Many thanks to Yannick Gravel for the patch fixing the plugin output and the fix on the test order 16 | * Many thanks to Scott Worthington for the ```--critical``` and ```--warning``` hints 17 | * Many thanks to Lawren Quigley-Jones for 18 | * the ```-A,--noauth``` patch and 19 | * the trap fix 20 | * Many thanks to Matthias Fuhrmeister for the ```-servername``` patch 21 | * Many thanks to Raphael Thoma for 22 | * the patch allowing HTTP to be specified as protocol and 23 | * the fix on ```-N``` with wildcards 24 | * Many thanks to Sven Nierlein for the client certificate authentication patch 25 | * Many thanks to Rob Yamry for the help in debugging a problem with certain versions of [OpenSSL](https://www.openssl.org) and TLS extensions 26 | * Many thanks to Jim Hopp for the "No certificate returned" enhancement patch 27 | * Many thanks to Javier Gonel for the TLS servername patch 28 | * Many thanks to Christian Ruppert for the XMPP patch 29 | * Many thanks to Robin H. Johnson for the ```timeout``` patch 30 | * Many thanks to Max Winterstein for the SSL version patch 31 | * Many thanks to Colin Smith for the RPM build Makefile patch 32 | * Many thanks to Andreas Dijkman for the RPM dependencies patch 33 | * Many thanks to Lawren Quigley-Jones for the common name patch 34 | * Many thanks to Ryan Nowakowski for the OCSP patch 35 | * Many thanks to Jérémy Lecour for the review and corrections 36 | * Many thanks to Mark Ruys for the OCSP patch 37 | * Many thanks to Milan Koudelka for the serial number patch 38 | * Many thanks to Konstantin Shalygin for the UTF-8 patch 39 | * Many thanks to Sam Richards for the SNI patch 40 | * Many thanks to [Sergei Shmanko](https://github.com/sshmanko) for the wildcard certificate patch 41 | * Many thanks to [juckerf](https://github.com/juckerf) for patch to increase control over which SSL/TLS versions to use 42 | * Many thanks to Rolf Eike Beer for the IRC and SMTP check patch 43 | * Many thanks to Viktor Szépe for the formatting and style patches 44 | * Many thanks to Philippe Kueck for the CN patch 45 | * Many thanks to [Ricardo](https://github.com/bb-Ricardo) for the date timestamp patch 46 | * Many thanks to [xert](https://github.com/xert) for the date timestamp patch 47 | * Many thanks to [xert](https://github.com/xert) for the [Qualys, SSL Labs](https://www.ssllabs.com/ssltest/) patch 48 | * Many thanks to [Leynos](https://github.com/leynos) for the OCSP proxy patch 49 | * Many thanks to Philippe Kueck for the selection of the cipher authentication 50 | * Many thanks to [Jalonet](https://github.com/jalonet) for the file/PEM patch 51 | * Many thanks to [Sander Cornelissen](https://github.com/scornelissen85)for the multiple CNs patch 52 | * Many thanks to [Pavel Rochnyak](https://github.com/rpv-tomsk) for the issuer certificate cache patch and the wildcard support in alternative names 53 | * Many thanks to [Vamp898](https://github.com/Vamp898) for the LDAP patch 54 | * Many thanks to Emilian Ertel for the [curl](https://curl.se) and ```date``` patches 55 | * Many thanks to Kosta Velikov for the ```grep``` patch 56 | * Many thanks to Vojtech Horky for the [OpenSSL](https://www.openssl.org) 1.1 patch 57 | * Many thanks to [Nicolas Lafont](https://github.com/ManicoW) for the Common Name fix 58 | * Many thanks to [d7415](https://github.com/d7415) for the ```-help``` patch 59 | * Many thanks to [Łukasz Wąsikowski](https://github.com/IdahoPL) for the [curl](https://curl.se) and date display patches 60 | * Many thanks to [booboo-at-gluga-de](https://github.com/booboo-at-gluga-de) for the CRL patch 61 | * Many thanks to [Georg](https://github.com/gbotti) for the fingerprint patch 62 | * Many thanks to [Wim van Ravesteijn](https://github.com/wimvr) for the DER encoded CRL files patch and the OCSP expiring date patch 63 | * Many thanks to [yasirathackersdotmu](https://github.com/yasirathackersdotmu) 64 | * Many thanks to [Christoph Moench-Tegeder](https://github.com/moench-tegeder) for the [curl](https://curl.se) patch 65 | * Many thanks to Dan Pritts for the ```--terse``` patch 66 | * Many thanks to [eeertel](https://github.com/eeertel) for the SNI warning patch 67 | * Many thanks to [Vojtech Horky](https://github.com/vhotspur) for the ```--format``` patch 68 | * Many thanks to [Markus Frosch](https://github.com/lazyfrosch) for the cleanup patch 69 | * Many thanks to [Ricardo Bartels](https://github.com/bb-Ricardo) for 70 | * the patch fixing unit tests, 71 | * the patch forlong output on Linux and 72 | * extending the issuer checks to the whole chain 73 | * Many thanks to [eimamagi](https://github.com/eimamagi) for the client key patch and for the CA file and directory support 74 | * Many thanks to Stefan Schlesinger for the ```HTTP_REQUEST``` patch 75 | * Many thanks to [sokol-44](https://github.com/sokol-44) for the HTTP request fix 76 | * Many thanks to [Jonas Meurer](https://github.com/mejo-) for the IMAP / IMAPS fix 77 | * Many thanks to [Mathieu Simon](https://github.com/matsimon) for the IMAPS, POP3S and LDAP patches 78 | * Many thanks to [Nico](https://github.com/nicox) for the [Qualys, SSL Labs](https://www.ssllabs.com/ssltest/) patch 79 | * Many thanks to [barakAtSoluto](https://github.com/barakAtSoluto) for the [Qualys, SSL Labs](https://www.ssllabs.com/ssltest/) warning patch 80 | * Many thanks to [Valentin Heidelberger](https://github.com/va1entin) for the [curl](https://curl.se) user agent patch 81 | * Many thanks to [Tone](https://github.com/anthonyhaussman) for the warning message improvement patch 82 | * Many thanks to [Michael Niewiara](https://github.com/mobitux)for the HTTPS/```echo``` fix 83 | * Many thanks to [Zadkiel](https://github.com/aslafy-z) for the extended regex patch and for the n-elementh check 84 | * Many thanks to [Dick Visser](https://github.com/dnmvisser) for the ```--inetproto``` patch 85 | * Many thanks to [jmuecke](https://github.com/jmuecke) for the multiple errors patch 86 | * Many thanks to [iasdeoupxe](https://github.com/iasdeoupxe) for various fixes 87 | * Many thanks to [Andre Klärner](https://github.com/klaernie) for the typos corrections 88 | * Many thanks to [Дилян Палаузов](https://github.com/dilyanpalauzov) for the DANE checks 89 | * Many thanks to [dupondje](https://github.com/dupondje) for the ```check_prog``` fix 90 | * Many thanks to [Jörg Thalheim](https://github.com/Mic92) for the ```xmpp-server``` patch 91 | * Many thanks to [Arkadiusz Miśkiewicz](https://github.com/arekm) for the OCSP timeout patch 92 | * Many thanks to [Thomas Weißschuh](https://github.com/t-8ch) for the [PostgreSQL](https://www.postgresql.org) patch 93 | * Many thanks to [Jonathan Besanceney](https://github.com/jonathan-besanceney) for the proxy patch 94 | * Many thanks to [grizzlydev-sarl](https://github.com/grizzlydev-sarl) for 95 | * the processing of all the certificate in the chain, 96 | * the verbose patch and 97 | * the output cleanup patch 98 | * Many thanks to [Claudio Kuenzler](https://github.com/Napsty) for the chain expiration output fix 99 | * Many thanks to [jf-vf](https://github.com/jf-vf) for the [MySQL](https://www.mysql.com) support patch 100 | * Many thanks to [skanx](https://github.com/skanx) for the ```--not-issued-by``` output patch 101 | * Many thanks to [Zadkiel](https://github.com/aslafy-z) for 102 | * the ```--version``` patch and 103 | * the ```--skip-element``` patch 104 | * Many thanks to [Marcel Burkhalter](https://github.com/explorer69) for the custom HTTP header patch. 105 | * Many thanks to [Peter Newman](https://github.com/peternewman) for 106 | * the timeout documentation patch and 107 | * the issuers patch 108 | * the PCKS12 extension patch 109 | * the spelling fixes and checks 110 | * and several other fixes 111 | * Many thanks to [cbiedl](https://github.com/cbiedl) for the proxy patch 112 | * Many thanks to [Robin Schneider](https://github.com/ypid-geberit) for the ```--long-output``` patch 113 | * Many thanks to [Robin Pronk](https://github.com/rfpronk) for the ```-u``` patch 114 | * Many thanks to [tunnelpr0](https://github.com/tunnelpr0) for the ```--inetproto``` patch 115 | * Many thanks to [Christoph Moench-Tegeder](https://github.com/moench-tegeder) for the [OpenSSL](https://www.openssl.org) version patch 116 | * Many thanks to [waja](https://github.com/waja) for 117 | * the [GitHub](https://www.github.com) workflows and 118 | * the chain checks with STARTTLS and 119 | * the trailing backslash patch 120 | * Many thanks to [Tobias Grünewald](https://github.com/tobias-gruenewald) for the client certificate patch 121 | * Many thanks to [chornberger-c2c](https://github.com/chornberger-c2c) for the critical and warning output fix 122 | * Many thanks to [Claus-Theodor Riegg](https://github.com/ctriegg-mak) for 123 | * the domain with underscores fix and 124 | * the certificate chain fix 125 | * Many thanks to [Ed Sabol](https://github.com/esabol) for the FQDN patch 126 | * Many thanks to [Igor Mironov](https://github.com/mcs6502) for the [LibreSSL](https://www.libressl.org) patch 127 | * Many thanks to [jalbstmeijer](https://github.com/jalbstmeijer) for 128 | * the [OpenSSL](https://www.openssl.org) patch and 129 | * the ```INETPROTO``` patch 130 | * Many thanks to [Pim Rupert](https://github.com/prupert) for the ```file(1)``` patches 131 | * Many thanks to [Alexander Aleksandrovič Klimov](https://github.com/Al2Klimov) for the DANE 312 patch 132 | * Many thanks to [Jaime Hablutzel](https://github.com/hablutzel1) for the ```--element``` fix 133 | * Many thanks to [Bernd Strößenreuther](https://github.com/booboo-at-gluga-de) for 134 | * the CRL fix, 135 | * the IPv6 fix and 136 | * for the floating point patch and 137 | * for the ```--help``` patch 138 | * Many thanks to [Kim Jahn](https://github.com/mookie-) for 139 | * the conversion typo and 140 | * the underscore fixes 141 | * Many thanks to [Naveen](https://github.com/naveensrinivasan) for the GitHub actions permissions fix 142 | * Many thanks to [Varac](https://github.com/varac) for the Prometheus fix 143 | * Many thanks to [PSSGCSim](https://github.com/PSSGCSim) for the Prometheus fix 144 | * Many thanks to [Dick Visser](https://github.com/dnmvisser) for the user agent fix 145 | * Many thanks to [claudioth](https://github.com/claudioth) for the Perl date computation fix 146 | * Many thanks to [Lukas Tribus](https://github.com/lukastribus) for the Python 3 patch 147 | * Many thanks to [Peter](https://github.com/Peter2121) for the FreeBSD jail patch 148 | * Many thanks to [Marcel Burkhalter](https://github.com/marcel-burkhalter) for the path check 149 | * Many thanks to [Slavko](https://github.com/slavkoja) for the RSA algorithms patch 150 | * Many thanks to [Ben Byrne](https://github.com/benbyr) for the CRL output format patch 151 | * Many thanks to [Tom Geißler](https://github.com/d7031) for the Icinga configuration 152 | * Many thanks to [Florian Apolloner](https://github.com/apollo13) for the configuration patch 153 | * Many thanks to [vanElden](https://github.com/vanElden) for the support to ignore unclean TLS shutdowns 154 | * Many thanks to [agibson2](https://github.com/agibson2) for the fingerprint patch 155 | * Many thanks to [Adam Cécile](https://github.com/eLvErDe) for the nmap SNI patch 156 | * Many thanks to [alvar](https://github.com/oxzi) for the configuration patch and the ```--dane``` option patch 157 | * Many thanks to [Michał Margula](https://github.com/alchemyx) for the ```--ignore-dh``` patch 158 | -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | cff-version: 1.2.0 2 | message: "If you use this software, please cite it as below." 3 | authors: 4 | - family-names: "Corti" 5 | given-names: "Matteo" 6 | orcid: "https://orcid.org/0000-0002-1746-1108" 7 | - family-names: "Палаузов" 8 | given-names: "Дилян" 9 | website: https://github.com/dilyanpalauzov 10 | - family-names: "Cécile" 11 | given-names: "Adam" 12 | website: https://github.com/eLvErDe 13 | - name: agibson2 14 | website: https://github.com/agibson2 15 | - name: Alexander Aleksandrovič Klimov 16 | website: https://github.com/Al2Klimov 17 | - name: alvar 18 | website: https://github.com/oxzi 19 | - family-names: "Klärner" 20 | given-names: "Andre" 21 | website: https://github.com/klaernie 22 | - family-names: "Dijkman" 23 | given-names: "Andreas" 24 | - family-names: "Miśkiewicz" 25 | given-names: "Arkadiusz" 26 | website: https://github.com/arekm 27 | - name: barakAtSoluto 28 | website: https://github.com/barakAtSoluto 29 | - family-names: "Byrne" 30 | given-names: "Ben" 31 | website: https://github.com/benbyr 32 | - family-names: "Strößenreuther" 33 | given-names: "Bernd" 34 | website: https://github.com/booboo-at-gluga-de 35 | - name: booboo-at-gluga-de 36 | website: https://github.com/booboo-at-gluga-de 37 | - name: cbiedl 38 | website: https://github.com/cbiedl 39 | - name: chornberger-c2c 40 | website: https://github.com/chornberger-c2c 41 | - family-names: "Ruppert" 42 | given-names: "Christian" 43 | - family-names: "Moench-Tegeder" 44 | given-names: "Christoph" 45 | website: https://github.com/moench-tegeder 46 | - family-names: "Kuenzler" 47 | given-names: "Claudio" 48 | website: https://github.com/Napsty 49 | - name: claudioth 50 | website: https://github.com/claudioth 51 | - family-names: "Riegg" 52 | given-names: "Claus-Theodor" 53 | website: https://github.com/ctriegg-mak 54 | - family-names: "Smith" 55 | given-names: "Colin" 56 | - name: d7415 57 | website: https://github.com/d7415 58 | - family-names: "Pritts" 59 | given-names: "Dan" 60 | - family-names: "Wallis" 61 | given-names: "Dan" 62 | - family-names: "Visser" 63 | given-names: "Dick" 64 | website: https://github.com/dnmvisser 65 | - name: dupondje 66 | website: https://github.com/dupondje 67 | - family-names: "Sabol" 68 | given-names: "Ed" 69 | website: https://github.com/esabol 70 | - name: eeertel 71 | website: https://github.com/eeertel 72 | - name: eimamagi 73 | website: https://github.com/eimamagi 74 | - family-names: "Ertel" 75 | given-names: "Emilian" 76 | - family-names: "Apolloner" 77 | given-names: "Florian" 78 | website: https://github.com/apollo13 79 | - name: Georg 80 | website: https://github.com/gbotti 81 | - name: grizzlydev-sarl 82 | website: https://github.com/grizzlydev-sarl 83 | - name: iasdeoupxe 84 | website: https://github.com/iasdeoupxe 85 | - family-names: "Mironov" 86 | given-names: "Igor" 87 | website: https://github.com/mcs6502 88 | - family-names: "Hablutzel" 89 | given-names: "Jaime" 90 | website: https://github.com/hablutzel1 91 | - name: jalbstmeijer 92 | website: https://github.com/jalbstmeijer 93 | - name: Jalonet 94 | website: https://github.com/jalonet 95 | - family-names: "Gonel" 96 | given-names: "Javier" 97 | - family-names: "Lecour" 98 | given-names: "Jérémy" 99 | - name: jf-vf 100 | website: https://github.com/jf-vf 101 | - family-names: "Hopp" 102 | given-names: "Jim" 103 | - name: jmuecke 104 | website: https://github.com/jmuecke 105 | - family-names: "Meurer" 106 | given-names: "Jonas" 107 | website: https://github.com/mejo- 108 | - family-names: "Besanceney" 109 | given-names: "Jonathan" 110 | website: https://github.com/jonathan-besanceney 111 | - family-names: "Thalheim" 112 | given-names: "Jörg" 113 | website: https://github.com/Mic92 114 | - name: juckerf 115 | website: https://github.com/juckerf 116 | - family-names: "McCormack" 117 | given-names: "Kenny" 118 | - family-names: "Jahn" 119 | given-names: "Kim" 120 | website: https://github.com/mookie- 121 | - family-names: "Shalygin" 122 | given-names: "Konstantin" 123 | - family-names: "Velikov" 124 | given-names: "Kosta" 125 | - family-names: "Quigley-Jones" 126 | given-names: "Lawren" 127 | - name: Leynos 128 | website: https://github.com/leynos 129 | - family-names: "Tribus" 130 | given-names: "Lukas" 131 | website: https://github.com/lukastribus 132 | - family-names: "Wąsikowski" 133 | given-names: "Łukasz" 134 | website: https://github.com/IdahoPL 135 | - family-names: "Fournier" 136 | given-names: "Marc" 137 | - family-names: "Burkhalter" 138 | given-names: "Marcel" 139 | website: https://github.com/explorer69 140 | - family-names: "Burkhalter" 141 | given-names: "Marcel" 142 | website: https://github.com/marcel-burkhalter 143 | - family-names: "Rejås" 144 | given-names: "Marcus" 145 | - family-names: "Ruys" 146 | given-names: "Mark" 147 | - family-names: "Frosch" 148 | given-names: "Markus" 149 | website: https://github.com/lazyfrosch 150 | - family-names: "Simon" 151 | given-names: "Mathieu" 152 | website: https://github.com/matsimon 153 | - family-names: "Fuhrmeister" 154 | given-names: "Matthias" 155 | - family-names: "Winterstein" 156 | given-names: "Max" 157 | - family-names: "Niewiara" 158 | given-names: "Michael" 159 | website: https://github.com/mobitux 160 | - family-names: "Margula" 161 | given-names: "Michał" 162 | website: https://github.com/alchemyx 163 | - family-names: "Koudelka" 164 | given-names: "Milan" 165 | - name: Naveen 166 | website: https://github.com/naveensrinivasan 167 | - name: Nico 168 | website: https://github.com/nicox 169 | - family-names: "Lafont" 170 | given-names: "Nicolas" 171 | website: https://github.com/ManicoW 172 | - family-names: "Rochnyak" 173 | given-names: "Pavel" 174 | website: https://github.com/rpv-tomsk 175 | - family-names: "Newman" 176 | given-names: "Peter" 177 | website: https://github.com/peternewman 178 | - name: Peter 179 | website: https://github.com/Peter2121 180 | - family-names: "Kueck" 181 | given-names: "Philippe" 182 | - family-names: "Rupert" 183 | given-names: "Pim" 184 | website: https://github.com/prupert 185 | - name: PSSGCSim 186 | website: https://github.com/PSSGCSim 187 | - family-names: "Thoma" 188 | given-names: "Raphael" 189 | - family-names: "Bartels" 190 | given-names: "Ricardo" 191 | website: https://github.com/bb-Ricardo 192 | - name: Ricardo 193 | website: https://github.com/bb-Ricardo 194 | - family-names: "Yamry" 195 | given-names: "Rob" 196 | - name: Robin H. Johnson 197 | - family-names: "Pronk" 198 | given-names: "Robin" 199 | website: https://github.com/rfpronk 200 | - family-names: "Schneider" 201 | given-names: "Robin" 202 | website: https://github.com/ypid-geberit 203 | - name: Rolf Eike Beer 204 | - family-names: "Nowakowski" 205 | given-names: "Ryan" 206 | - family-names: "Richards" 207 | given-names: "Sam" 208 | - family-names: "Cornelissen" 209 | given-names: "Sander" 210 | website: https://github.com/scornelissen85 211 | - family-names: "Worthington" 212 | given-names: "Scott" 213 | - family-names: "Shmanko" 214 | given-names: "Sergei" 215 | website: https://github.com/sshmanko 216 | - name: skanx 217 | website: https://github.com/skanx 218 | - name: Slavko 219 | website: https://github.com/slavkoja 220 | - name: sokol-44 221 | website: https://github.com/sokol-44 222 | - family-names: "Schlesinger" 223 | given-names: "Stefan" 224 | - family-names: "Nierlein" 225 | given-names: "Sven" 226 | - family-names: "Weißschuh" 227 | given-names: "Thomas" 228 | website: https://github.com/t-8ch 229 | - family-names: "Grünewald" 230 | given-names: "Tobias" 231 | website: https://github.com/tobias-gruenewald 232 | - family-names: "Geißler" 233 | given-names: "Tom" 234 | website: https://github.com/d7031 235 | - name: Tone 236 | website: https://github.com/anthonyhaussman 237 | - name: tunnelpr0 238 | website: https://github.com/tunnelpr0 239 | - family-names: "Haarala" 240 | given-names: "Tuomas" 241 | - family-names: "Heidelberger" 242 | given-names: "Valentin" 243 | website: https://github.com/va1entin 244 | - name: Vamp898 245 | website: https://github.com/Vamp898 246 | - name: vanElden 247 | website: https://github.com/vanElden 248 | - name: Varac 249 | website: https://github.com/varac 250 | - family-names: "Szépe" 251 | given-names: "Viktor" 252 | - family-names: "Horky" 253 | given-names: "Vojtech" 254 | - family-names: "Horky" 255 | given-names: "Vojtech" 256 | website: https://github.com/vhotspur 257 | - name: waja 258 | website: https://github.com/waja 259 | - name: Wim van Ravesteijn 260 | website: https://github.com/wimvr 261 | - family-names: "Schricker" 262 | given-names: "Wolfgang" 263 | - name: xert 264 | website: https://github.com/xert 265 | - family-names: "Gravel" 266 | given-names: "Yannick" 267 | - name: yasirathackersdotmu 268 | website: https://github.com/yasirathackersdotmu 269 | - name: Zadkiel 270 | website: https://github.com/aslafy-z 271 | title: "check_ssl_cert" 272 | version: 2.93.0 273 | date-released: 2025-05-27 274 | url: "https://github.com/matteocorti/check_ssl_cert" 275 | repository-code: "https://github.com/matteocorti/check_ssl_cert" 276 | keywords: 277 | - "certificate" 278 | - "openssl" 279 | - "shell-script" 280 | - "nagios-plugin" 281 | abstract: A shell script (that can be used as a Nagios/Icinga plugin) to check an SSL/TLS connection. 282 | contact: 283 | - email: matteo@corti.li 284 | family-names: Corti 285 | given-names: Matteo 286 | type: software 287 | license: GPL-3.0 288 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socioeconomic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at matteo@corti.li. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], [version 1.4](https://www.contributor-covenant.org/version/1/4/code-of-conduct.html) 71 | 72 | [homepage]: https://www.contributor-covenant.org 73 | 74 | For answers to common questions about this code of conduct, see 75 | [https://www.contributor-covenant.org/faq](https://www.contributor-covenant.org/faq) 76 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | ## Submitting bugs 4 | 5 | When reporting a bug please include as much information as possible. Include the output of the plugin with the `-verbose` and `-debug` options. 6 | 7 | If possible give a real-life example that can be tested (e.g., a public host). 8 | 9 | If you do not want that the host name is published a bug report, but the host is reachable from the internet, please send me the host name per email ([matteo@corti.li](mailto:matteo@corti.li)) so that I can test. I will keep the host name confidential. 10 | 11 | ## Submitting changes 12 | 13 | * Always write clear log messages for your commits 14 | * Check the code with [ShellCheck](https://www.shellcheck.net) (```make shellckeck```) 15 | * Always format the code with [shfmt](https://github.com/mvdan/sh) 16 | * Check the spelling with [codespell](https://github.com/codespell-project/codespell) (```make codespell```) 17 | * Always log your changes in the ChangeLog file 18 | * Always test the changes `make test` and be sure that all the tests are passed 19 | * If possible write some tests to validate the changes you did to the plugin 20 | -------------------------------------------------------------------------------- /COPYRIGHT.md: -------------------------------------------------------------------------------- 1 | 2 | # Copyright 3 | 4 | * Copyright © 2007-2013 ETH Zurich 5 | * Copyright © 2007-2025 Matteo Corti 6 | 7 | with the following individuals added to the list of contributing authors 8 | 9 | * Dan Wallis 10 | * Lawren Quigley-Jones 11 | * Marc Fournier 12 | * Marcus Rejås 13 | * Matteo Corti 14 | * Matthias Fuhrmeister 15 | * Raphael Thoma 16 | * Scott Worthington 17 | * Sven Nierlein 18 | * Tuomas Haarala 19 | * Wolfgang Schricker 20 | * Yannick Gravel 21 | * Jim Hopp 22 | * Javier Gonel 23 | * Christian Ruppert 24 | * Robin H. Johnson 25 | * Max Winterstein 26 | * Colin Smith 27 | * Andreas Dijkman 28 | * Ryan Nowakowski 29 | * Jérémy Lecour 30 | * Mark Ruys 31 | * Milan Koudelka 32 | * Konstantin Shalygin 33 | * Sam Richards 34 | * Sergei Shmanko 35 | * Rolf Eike Beer 36 | * Viktor Szépe 37 | * Philippe Kueck 38 | * Sander Cornelissen 39 | * Pavel Rochnyak 40 | * [Vamp898](https://github.com/Vamp898) 41 | * Emilian Ertel 42 | * Kosta Velikov 43 | * Vojtech Horky 44 | * [Nicolas Lafont](https://github.com/ManicoW) 45 | * [d7415](https://github.com/d7415) 46 | * [Łukasz Wąsikowski](https://github.com/IdahoPL) 47 | * [booboo-at-gluga-de](https://github.com/booboo-at-gluga-de) 48 | * [Georg](https://github.com/gbotti) 49 | * [Wim van Ravesteijn](https://github.com/wimvr) 50 | * [yasirathackersdotmu](https://github.com/yasirathackersdotmu) 51 | * [Christoph Moench-Tegeder](https://github.com/moench-tegeder) 52 | * Dan Pritts 53 | * [eeertel](https://github.com/eeertel) 54 | * [Vojtech Horky](https://github.com/vhotspur) 55 | * [Markus Frosch](https://github.com/lazyfrosch) 56 | * [Ricardo Bartels](https://github.com/bb-Ricardo) 57 | * [eimamagi](https://github.com/eimamagi) 58 | * Stefan Schlesinger 59 | * [sokol-44](https://github.com/sokol-44) 60 | * [Jonas Meurer](https://github.com/mejo-) 61 | * [Mathieu Simon](https://github.com/matsimon) 62 | * [Nico](https://github.com/nicox) 63 | * [barakAtSoluto](https://github.com/barakAtSoluto) 64 | * [Valentin Heidelberger](https://github.com/va1entin) 65 | * [Tone](https://github.com/anthonyhaussman) 66 | * [Michael Niewiara](https://github.com/mobitux) 67 | * [Zadkiel](https://github.com/aslafy-z) 68 | * [Dick Visser](https://github.com/dnmvisser) 69 | * [jmuecke](https://github.com/jmuecke) 70 | * [iasdeoupxe](https://github.com/iasdeoupxe) 71 | * [Andre Klärner](https://github.com/klaernie) 72 | * [Дилян Палаузов](https://github.com/dilyanpalauzov) 73 | * [dupondje](https://github.com/dupondje) 74 | * [Jörg Thalheim](https://github.com/Mic92) 75 | * [Arkadiusz Miśkiewicz](https://github.com/arekm) 76 | * [Thomas Weißschuh](https://github.com/t-8ch) 77 | * [Jonathan Besanceney](https://github.com/jonathan-besanceney) 78 | * [grizzlydev-sarl](https://github.com/grizzlydev-sarl) 79 | * [Claudio Kuenzler](https://github.com/Napsty) 80 | * [jf-vf](https://github.com/jf-vf) 81 | * [skanx](https://github.com/skanx) 82 | * [Zadkiel](https://github.com/aslafy-z) 83 | * [Marcel Burkhalter](https://github.com/explorer69) 84 | * [Peter Newman](https://github.com/peternewman) 85 | * [cbiedl](https://github.com/cbiedl) 86 | * [Robin Schneider](https://github.com/ypid-geberit) 87 | * [Robin Pronk](https://github.com/rfpronk) 88 | * [tunnelpr0](https://github.com/tunnelpr0) 89 | * [Christoph Moench-Tegeder](https://github.com/moench-tegeder) 90 | * [waja](https://github.com/waja) 91 | * [Tobias Grünewald](https://github.com/tobias-gruenewald) 92 | * [chornberger-c2c](https://github.com/chornberger-c2c) 93 | * [Claus-Theodor Riegg](https://github.com/ctriegg-mak) 94 | * [Ed Sabol](https://github.com/esabol) 95 | * [Igor Mironov](https://github.com/mcs6502) 96 | * [jalbstmeijer](https://github.com/jalbstmeijer) 97 | * [Pim Rupert](https://github.com/prupert) 98 | * [Alexander Aleksandrovič Klimov](https://github.com/Al2Klimov) 99 | * [Jaime Hablutzel](https://github.com/hablutzel1) 100 | * [Bernd Strößenreuther](https://github.com/booboo-at-gluga-de) 101 | * Kim Jahn 102 | 103 | This program is free software; you can redistribute it and/or modify 104 | it under the terms of the GNU General Public License as published by 105 | the Free Software Foundation; either version 3 of the License, or (at 106 | your option) any later version. 107 | 108 | This program is distributed in the hope that it will be useful, but 109 | WITHOUT ANY WARRANTY; without even the implied warranty of 110 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 111 | General Public License for more details. 112 | 113 | You should have received a copy of the GNU General Public License 114 | along with this program; if not, write to the Free Software 115 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 116 | -------------------------------------------------------------------------------- /GNUmakefile: -------------------------------------------------------------------------------- 1 | PLUGIN=check_ssl_cert 2 | VERSION=`cat VERSION` 3 | DIST_DIR=$(PLUGIN)-$(VERSION) 4 | 5 | # files to be included in the distribution 6 | DIST_FILES=AUTHORS.md COPYING.md ChangeLog INSTALL.md Makefile GNUmakefile NEWS.md README.md VERSION $(PLUGIN) $(PLUGIN).spec COPYRIGHT.md ${PLUGIN}.1 CITATION.cff check_ssl_cert.completion check_ssl_cert_icinga2.conf 7 | 8 | # this year 9 | YEAR=`date +"%Y"` 10 | 11 | # file to be checked for formatting 12 | FORMATTED_FILES=test/unit_tests.sh test/integration_tests.sh test/badssl_tests.sh ChangeLog INSTALL.md Makefile VERSION $(PLUGIN) $(PLUGIN).spec COPYRIGHT.md ${PLUGIN}.1 .github/workflows/* utils/*.sh check_ssl_cert.completion 13 | 14 | # shell scripts (to be checked with ShellCheck) 15 | SCRIPTS=check_ssl_cert test/*.sh utils/*.sh 16 | 17 | XATTRS_OPTION := $(shell if tar --help 2>&1 | grep -q bsdtar ; then echo '--no-xattrs' ; fi ) 18 | 19 | .PHONY: install clean test rpm distclean check version_check codespell integration_tests unit_tests integration_tests_with_proxy unit_tests_with_proxy 20 | 21 | all: dist 22 | 23 | # checks if the version is updated in all the files 24 | version_check: CITATION.cff 25 | @echo "Checking version $(VERSION)" 26 | grep -q "VERSION *= *[\'\"]*$(VERSION)" $(PLUGIN) 27 | grep -q "^%global version *$(VERSION)" $(PLUGIN).spec 28 | grep -q -F -- "- $(VERSION)-" $(PLUGIN).spec 29 | grep -q "\"$(VERSION)\"" $(PLUGIN).1 30 | grep -q -F "${VERSION}" NEWS.md 31 | grep -q "^version: ${VERSION}" CITATION.cff 32 | @echo "Version check: OK" 33 | 34 | # builds the release files 35 | dist: version_check CITATION.cff 36 | rm -rf $(DIST_DIR) $(DIST_DIR).tar.gz 37 | mkdir $(DIST_DIR) 38 | cp -r $(DIST_FILES) $(DIST_DIR) 39 | # avoid to include extended attribute data files 40 | # see https://superuser.com/questions/259703/get-mac-tar-to-stop-putting-filenames-in-tar-archives 41 | export COPY_EXTENDED_ATTRIBUTES_DISABLE=true; \ 42 | export COPYFILE_DISABLE=true; \ 43 | tar $(XATTRS_OPTION) -c -z -f $(DIST_DIR).tar.gz $(DIST_DIR) && \ 44 | tar $(XATTRS_OPTION) -c -j -f $(DIST_DIR).tar.bz2 $(DIST_DIR) 45 | 46 | 47 | 48 | install: 49 | ifndef DESTDIR 50 | @echo "Please define DESTDIR and MANDIR variables with the installation targets" 51 | @echo "e.g, make DESTDIR=/nagios/plugins/dir MANDIR=/nagios/plugins/man/dir install" 52 | @echo 53 | @echo "If you are using 'sudo' please specify the '-E, --preserve-env' option" 54 | else 55 | mkdir -p $(DESTDIR) 56 | install -m 755 $(PLUGIN) $(DESTDIR) 57 | mkdir -p ${MANDIR}/man1 58 | install -m 644 ${PLUGIN}.1 ${MANDIR}/man1/ 59 | endif 60 | ifdef COMPLETIONDIR 61 | mkdir -p $(COMPLETIONDIR) 62 | install -m 644 check_ssl_cert.completion $(COMPLETIONDIR)/check_ssl_cert 63 | endif 64 | 65 | COMPLETIONS_DIR := $(shell pkg-config --variable=completionsdir bash-completion) 66 | install_bash_completion: 67 | ifdef COMPLETIONS_DIR 68 | cp check_ssl_cert.completion $(COMPLETIONS_DIR)/check_ssl_cert 69 | endif 70 | 71 | CITATION.cff: AUTHORS.md VERSION NEWS.md 72 | ./utils/update_citation.sh 73 | 74 | # we check for tabs 75 | # and remove trailing blanks 76 | formatting_check: 77 | ! grep -q '[[:blank:]]$$' $(FORMATTED_FILES) 78 | 79 | CODESPELL := $(shell command -v codespell 2> /dev/null ) 80 | # spell check 81 | codespell: 82 | ifndef CODESPELL 83 | @echo "no codespell installed" 84 | else 85 | codespell \ 86 | . 87 | endif 88 | 89 | SHFMT := $(shell command -v shfmt 2> /dev/null) 90 | format: 91 | ifndef SHFMT 92 | @echo "No shfmt installed" 93 | else 94 | # -p POSIX 95 | # -w write to file 96 | # -s simplify 97 | # -i 4 indent with 4 spaces 98 | shfmt -p -w -s -i 4 $(SCRIPTS) 99 | shfmt -ln bash -w -s -i 4 check_ssl_cert.completion 100 | endif 101 | 102 | clean: 103 | find . -name "*~" -delete 104 | find . -name "*.bak" -delete 105 | find . -name "#*#" -delete 106 | rm -rf rpmroot 107 | 108 | distclean: clean 109 | rm -rf check_ssl_cert-[0-9]* 110 | rm -f *.crt 111 | rm -f *.error 112 | rm -f headers.txt 113 | 114 | check: test 115 | 116 | SHELLCHECK := $(shell command -v shellcheck 2> /dev/null) 117 | SHUNIT := $(shell if [ -z "${SHUNIT2}" ] ; then command -v shunit2 2> /dev/null || if [ -x /usr/share/shunit2/shunit2 ] ; then echo /usr/share/shunit2/shunit2 ; fi; else echo "${SHUNIT2}"; fi ) 118 | 119 | distcheck: disttest 120 | disttest: dist formatting_check shellcheck codespell 121 | ./utils/check_documentation.sh 122 | man ./check_ssl_cert.1 > /dev/null 123 | 124 | test: formatting_check shellcheck unit_tests integration_tests badssl_tests badssl_tests_with_proxy unit_tests_with_proxy integration_tests_with_proxy 125 | 126 | unit_tests: 127 | ifndef SHUNIT 128 | @echo "No shUnit2 installed: see README.md" 129 | exit 1 130 | else 131 | ( export SHUNIT2=$(SHUNIT) && export LC_ALL=C && cd test && ./unit_tests.sh ) 132 | endif 133 | 134 | unit_tests_with_proxy: 135 | ifndef SHUNIT 136 | @echo "No shUnit2 installed: see README.md" 137 | exit 1 138 | else 139 | ./utils/start_proxy.sh ./test/tinyproxy.conf 140 | ( export SHUNIT2=$(SHUNIT) && export http_proxy=127.0.0.1:8888 && export LC_ALL=C && cd test && ./unit_tests.sh ) 141 | killall tinyproxy 142 | sleep 1 143 | endif 144 | 145 | integration_tests: 146 | ifndef SHUNIT 147 | @echo "No shUnit2 installed: see README.md" 148 | exit 1 149 | else 150 | ( export SHUNIT2=$(SHUNIT) && export LC_ALL=C && cd test && ./integration_tests.sh ) 151 | endif 152 | 153 | integration_tests_with_proxy: 154 | ifndef SHUNIT 155 | @echo "No shUnit2 installed: see README.md" 156 | exit 1 157 | else 158 | ./utils/start_proxy.sh ./test/tinyproxy.conf 159 | ( export SHUNIT2=$(SHUNIT) && export http_proxy=127.0.0.1:8888 && export LC_ALL=C && cd test && ./integration_tests.sh ) 160 | killall tinyproxy 161 | sleep 1 162 | endif 163 | 164 | badssl_tests: 165 | ifndef SHUNIT 166 | @echo "No shUnit2 installed: see README.md" 167 | exit 1 168 | else 169 | ( export SHUNIT2=$(SHUNIT) && export LC_ALL=C && cd test && ./badssl_tests.sh ) 170 | endif 171 | 172 | badssl_tests_with_proxy: 173 | ifndef SHUNIT 174 | @echo "No shUnit2 installed: see README.md" 175 | exit 1 176 | else 177 | ./utils/start_proxy.sh ./test/tinyproxy.conf 178 | ( export SHUNIT2=$(SHUNIT) && export http_proxy=127.0.0.1:8888 && export LC_ALL=C && cd test && ./badssl_tests.sh ) 179 | killall tinyproxy 180 | sleep 1 181 | endif 182 | 183 | shellcheck: 184 | ifndef SHELLCHECK 185 | @echo "No shellcheck installed: skipping check" 186 | else 187 | if shellcheck --help 2>&1 | grep -q -- '-o ' ; then shellcheck -o all $(SCRIPTS) ; else shellcheck $(SCRIPTS) ; fi 188 | endif 189 | 190 | rpm: dist 191 | mkdir -p rpmroot/SOURCES rpmroot/BUILD 192 | cp $(DIST_DIR).tar.gz rpmroot/SOURCES 193 | rpmbuild --define "_topdir `pwd`/rpmroot" -ba check_ssl_cert.spec 194 | -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | # check\_ssl\_check 2 | 3 | ## Requirements 4 | 5 | * ```bc``` 6 | * [curl](https://curl.se) 7 | * ```date``` 8 | * ```file``` 9 | * ```host``` 10 | * [nmap](https://nmap.org) 11 | * [OpenSSL](https://www.openssl.org) 12 | 13 | ## Optional dependencies 14 | 15 | * check\_ssl\_cert requires [```expect```](http://en.wikipedia.org/wiki/Expect) or [```timeout```](https://man7.org/linux/man-pages/man1/timeout.1.html) to enable timeouts. If ```expect``` or ```timeout``` are not present on your system timeouts will be disabled. 16 | * ```dig``` for 17 | * DANE checks 18 | * DNSSEC checks 19 | * [gmake](https://www.gnu.org/software/make/) on [FreeBSD](https://www.freebsd.org) 20 | * ```expand``` for ```--info``` 21 | * ```tar``` and ```bzip2``` to build release packages 22 | * ```ip``` or ```ifconfig``` to be able to use the ```-4``` and ```-6``` options 23 | * [nectcat](https://nc110.sourceforge.io) for ```--ignore-connection-state``` 24 | * Python 3.0 for the TDS (Tabular Data Stream) protocol check 25 | * Java for KeyStore checks 26 | 27 | ## Development 28 | 29 | Following tools are required for development: 30 | 31 | * [shUnit2](https://github.com/kward/shunit2) for the tests 32 | * [shfmt](https://github.com/mvdan/sh) to format the source files 33 | * [ShellCheck](https://www.shellcheck.net) for the code quality checks 34 | * [codespell](https://github.com/codespell-project/codespell) for the spelling checks 35 | * ```dig``` for IPv6 tests 36 | 37 | You can check the installed dependencies with the ```utils/check_deps.sh``` script. 38 | 39 | ## Installation 40 | 41 | * You can run the plugin from the shell. 42 | * If you want to install it systemwide, copy the plugin to a directory in the path, and ```check_ssl_cert.1``` in an appropriate directory in the ```$MANPATH``` 43 | * Simply copy the plugin to your Nagios/Icinga plugin directory (e.g., ```/usr/lib64/nagios/plugins/```) 44 | * Use ```make install``` by defining the ```DESTDIR``` and ```MANDIR``` variables with the installation targets. E.g, ```make DESTDIR=/nagios/plugins/dir MANDIR=/nagios/plugins/man/dir install``` or ```sudo make -E DESTDIR=/usr/local/bin MANDIR=/usr/local/man``` 45 | * To install the bash completion script run ```sudo make install_bash_completion``` (it will install the completion script in the directory defined by ```pkg-config --variable=completionsdir bash-completion```) 46 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Wrapper for make which do not support ifdef 2 | # 3 | # See: https://stackoverflow.com/questions/45342191/the-make-on-freebsd-doesnt-support-ifdef-directives 4 | # 5 | 6 | GNUMAKE?= gmake 7 | 8 | all: 9 | ${GNUMAKE} $@ 10 | 11 | .DEFAULT: 12 | ${GNUMAKE} $@ 13 | 14 | .PHONY: all test install 15 | -------------------------------------------------------------------------------- /RELEASE_NOTES.md: -------------------------------------------------------------------------------- 1 | No error when checking an expired certificate in a file with ```--ignore-exp``` 2 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting a Vulnerability 4 | 5 | Please contact the [matteo@corti.li](mailto:matteo@corti.li) directly 6 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 2.93.0 2 | -------------------------------------------------------------------------------- /check_ssl_cert.1: -------------------------------------------------------------------------------- 1 | .\" Process this file with 2 | .\" groff -man -Tascii check_ssl_cert.1 3 | .\" 4 | .TH "check_ssl_cert" 1 "May, 2025" "2.93.0" "USER COMMANDS" 5 | .SH NAME 6 | check_ssl_cert \- checks the validity of X.509 certificates 7 | .SH SYNOPSIS 8 | .BR "check_ssl_cert " "-H host [OPTIONS]" 9 | .br 10 | .BR "check_ssl_cert " "-f file [OPTIONS]" 11 | .SH DESCRIPTION 12 | .B check_ssl_cert 13 | A shell script (that can be used as a Nagios/Icinga plugin) to check an SSL/TLS connection 14 | .SH ARGUMENTS 15 | .TP 16 | .BR "-f,--file" " file" 17 | Local file path or URI. With -f you can not only pass a x509 certificate file but also a certificate revocation list (CRL) to check the validity period or a Java KeyStore file 18 | .TP 19 | .BR "-H,--host" " host" 20 | server 21 | .SH OPTIONS 22 | .TP 23 | .BR "-A,--noauth" 24 | Ignore authority warnings (expiration only) 25 | .TP 26 | .BR " --all" 27 | Enable all the possible optional checks at the maximum level 28 | .TP 29 | .BR " --all-local" 30 | Enable all the possible optional checks at the maximum level (without SSL-Labs) 31 | .TP 32 | .BR " --allow-empty-san" 33 | Allow certificates without Subject Alternative Names (SANs) 34 | .TP 35 | .BR "-C,--clientcert" " path" 36 | Use client certificate to authenticate 37 | .TP 38 | .BR "-c,--critical" " days" 39 | Minimum number of days a certificate has to be valid to issue a critical status. Can be a floating point number, e.g., 0.5. Default: 15 40 | .TP 41 | .BR " --check-chain" 42 | The certificate chain cannot contain double or root certificates 43 | .TP 44 | .BR " --check-ciphers" " grade" 45 | Check the offered ciphers 46 | .TP 47 | .BR " --check-ciphers-warnings" 48 | Critical if nmap reports a warning for an offered cipher 49 | .TP 50 | .BR " --check-http-headers" 51 | Check the HTTP headers for best practices 52 | .TP 53 | .BR " --check-ssl-labs-warn grade" 54 | SSL Labs grade on which to warn 55 | .TP 56 | .BR " --clientpass" " phrase" 57 | Set passphrase for client certificate. 58 | .TP 59 | .BR " --configuration" " file" 60 | Read options from the specified file 61 | .TP 62 | .BR " --crl" 63 | Check revocation via CRL (requires --rootcert-file) 64 | .TP 65 | .BR " --curl-bin" " path" 66 | Path of the curl binary to be used 67 | .TP 68 | .BR " --custom-http-header" " string" 69 | Custom HTTP header sent when getting the cert example: 'X-Check-Ssl-Cert: Foobar=1' 70 | .TP 71 | .BR " --dane" 72 | Verify that valid DANE records exist (since OpenSSL 1.1.0) 73 | .TP 74 | .BR " --dane 211" 75 | Verify that a valid DANE-TA(2) SPKI(1) SHA2-256(1) TLSA record exists 76 | .TP 77 | .BR " --dane 301" 78 | Verify that a valid DANE-EE(3) Cert(0) SHA2-256(1) TLSA record exists 79 | .TP 80 | .BR " --dane 302" 81 | Verify that a valid DANE-EE(3) Cert(0) SHA2-512(2) TLSA record exists 82 | .TP 83 | .BR " --dane 311" 84 | Verify that a valid DANE-EE(3) SPKI(1) SHA2-256(1) TLSA record exists 85 | .TP 86 | .BR " --dane 312" 87 | Verify that a valid DANE-EE(3) SPKI(1) SHA2-512(1) TLSA record exists 88 | .TP 89 | .BR " --date" " path" 90 | Path of the date binary to be used 91 | .TP 92 | .BR "-d,--debug" 93 | Produce debugging output (can be specified more than once) 94 | .TP 95 | .BR " --debug-cert" 96 | Store the retrieved certificates in the current directory 97 | .TP 98 | .BR " --debug-file" " file" 99 | Write the debug messages to file 100 | .TP 101 | .BR " --debug-headers" 102 | Store the retrieved HTLM headers in the headers.txt file 103 | .TP 104 | .BR " --debug-time" 105 | Write timing information in the debugging output 106 | .TP 107 | .BR " --default-format" 108 | Print the default output format and exit 109 | .TP 110 | .BR " --dig-bin" " path" 111 | Path of the dig binary to be used 112 | .TP 113 | .BR " --do-not-resolve" 114 | Do not check if the host can be resolved 115 | .TP 116 | .BR " --dtls" 117 | Use the DTLS protocol 118 | .TP 119 | .BR " --dtls1" 120 | Use the DTLS protocol 1.0 121 | .TP 122 | .BR " --dtls1_2" 123 | Use the DTLS protocol 1.2 124 | .TP 125 | .BR "-e,--email" " address" 126 | Pattern (extended regular expression) to match the email address contained in the certificate. You can specify different addresses separated by a pipe (e.g., 'addr1|addr2') 127 | .TP 128 | .BR " --ecdsa" 129 | Signature algorithm selection: force ECDSA certificate 130 | .TP 131 | .BR " --element" " number" 132 | Check up to the N cert element from the beginning of the chain 133 | .TP 134 | .BR " --file-bin" " path" 135 | Path of the file binary to be used 136 | .TP 137 | .BR " --fingerprint" " hash" 138 | Pattern to match the fingerprint 139 | .TP 140 | .BR " --fingerprint-alg" " algorithm" 141 | Algorithm for fingerprint. Default sha1 142 | .TP 143 | .BR " --first-element-only" 144 | Verify just the first cert element, not the whole chain 145 | .TP 146 | .BR " --force-dconv-date" 147 | Force the usage of dconv for date computations 148 | .TP 149 | .BR " --force-perl-date" 150 | Force the usage of Perl for date computations 151 | .TP 152 | .BR " --format" " FORMAT" 153 | Format output template on success, for example: '%SHORTNAME% OK %CN% from %CA_ISSUER_MATCHED%' 154 | .br 155 | List of possible variables: 156 | .br 157 | - %CA_ISSUER_MATCHED% 158 | .br 159 | - %CHECKEDNAMES% 160 | .br 161 | - %CN% 162 | .br 163 | - %DATE% 164 | .br 165 | - %DAYS_VALID% 166 | .br 167 | - %DYSPLAY_CN% 168 | .br 169 | - %HOST% 170 | .br 171 | - %OCSP_EXPIRES_IN_HOURS% 172 | .br 173 | - %OPENSSL_COMMAND% 174 | .br 175 | - %PORT% 176 | .br 177 | - %SELFSIGNEDCERT% 178 | .br 179 | - %SHORTNAME% 180 | .br 181 | - %SIGALGO% 182 | .br 183 | - %SSL_LABS_HOST_GRADE% 184 | .br 185 | See --default-format for the default 186 | .TP 187 | .BR " --grep-bin" " path" 188 | Path of the grep binary to be used 189 | .TP 190 | .BR "-h,--help,-?" 191 | This help message 192 | .TP 193 | .BR " --http-headers-path" " path" 194 | The path to be used to fetch HTTP headers 195 | .TP 196 | .BR " --http-use-get" 197 | Use GET instead of HEAD (default) for the HTTP related checks 198 | .TP 199 | .BR "-i,--issuer" " issuer" 200 | Pattern (extended regular expression) to match the issuer of the certificate. You can specify different issuers separated by a pipe (e.g., 'issuer1|issuer2') 201 | .TP 202 | .BR " --ignore-altnames" 203 | Ignore alternative names when matching pattern specified in -n (or the host name) 204 | .TP 205 | .BR " --ignore-connection-problems" " [state]" 206 | In case of connection problems returns OK or the optional state 207 | .TP 208 | .BR " --ignore-crl" 209 | Ignore CRLs 210 | .TP 211 | .BR " --ignore-dh" 212 | Ignore too small DH keys 213 | .TP 214 | .BR " --ignore-exp" 215 | Ignore expiration date 216 | .TP 217 | .BR " --ignore-http-headers" 218 | Ignore checks on HTTP headers with --all and --all-local 219 | .TP 220 | .BR " --ignore-host-cn" 221 | Do not complain if the CN does not match the host name 222 | .TP 223 | .BR " --ignore-incomplete-chain" 224 | Do not check chain integrity 225 | .TP 226 | .BR " --ignore-maximum-validity" 227 | Ignore the certificate maximum validity 228 | .TP 229 | .BR " --ignore-ocsp" 230 | Do not check revocation with OCSP 231 | .TP 232 | .BR " --ignore-ocsp-errors" 233 | Continue if the OCSP status cannot be checked 234 | .TP 235 | .BR " --ignore-ocsp-timeout" 236 | Ignore OCSP result when timeout occurs while checking 237 | .TP 238 | .BR " --ignore-sct" 239 | Do not check for signed certificate timestamps (SCT) 240 | .TP 241 | .BR " --ignore-sig-alg" 242 | Do not check if the certificate was signed with SHA1 or MD5 243 | .TP 244 | .BR " --ignore-ssl-labs-cache" 245 | Force a new check by SSL Labs (see -L) 246 | .TP 247 | .BR " --ignore-ssl-labs-errors" 248 | Ignore errors if SSL Labs is not accessible or times out 249 | .TP 250 | .BR " --ignore-tls-renegotiation" 251 | Ignore the TLS renegotiation check 252 | .TP 253 | .BR " --ignore-unexpected-eof" 254 | Ignore unclean TLS shutdowns 255 | .TP 256 | .BR " --inetproto protocol" 257 | Force IP version 4 or 6 258 | .TP 259 | .BR " --info" 260 | Print certificate information 261 | .TP 262 | .BR " --init-host-cache" 263 | Initialize the host cache 264 | .TP 265 | .BR " --issuer-cert-cache" " dir" 266 | Directory where to store issuer certificates cache 267 | .TP 268 | .BR " --jks-alias" " alias" 269 | Alias name of the Java KeyStore entry (requires --file) 270 | .TP 271 | .BR "-K,--clientkey" " path" 272 | Use client certificate key to authenticate 273 | .TP 274 | .BR "-L,--check-ssl-labs grade" 275 | SSL Labs assessment (please check https://www.ssllabs.com/about/terms.html). Critical if the grade is lower than specified. 276 | .TP 277 | .BR " --long-output" " list" 278 | Append the specified comma separated (no spaces) list of attributes to the plugin output on additional lines. 279 | Valid attributes are: enddate, startdate, subject, issuer, modulus, serial, hash, email, ocsp_uri and fingerprint. 'all' will include all the available attributes. 280 | .TP 281 | .BR "-m,--match" " name" 282 | Pattern to match the CN or AltName (can be specified multiple times) 283 | .TP 284 | .BR " --maximum-validity" " [days]" 285 | The maximum validity of the certificate must not exceed 'days' (default 397). This check is automatic for HTTPS 286 | .TP 287 | .BR " --nmap-bin" " path" 288 | Path of the nmap binary to be used 289 | .TP 290 | .BR " --nmap-with-proxy" 291 | Allow nmap to be used with a proxy 292 | .TP 293 | .BR " --no-perf" 294 | Do not show performance data 295 | .TP 296 | .BR " --no-proxy" 297 | Ignore the http_proxy and https_proxy environment variables 298 | .TP 299 | .BR " --no-proxy-curl" 300 | Ignore the http_proxy and https_proxy environment variables for curl 301 | .TP 302 | .BR " --no-proxy-s_client" 303 | Ignore the http_proxy and https_proxy environment variables for openssl s_client 304 | .TP 305 | .BR " --no-ssl2" 306 | Disable SSL version 2 307 | .TP 308 | .BR " --no-ssl3" 309 | Disable SSL version 3 310 | .TP 311 | .BR " --no-tls1" 312 | Disable TLS version 1 313 | .TP 314 | .BR " --no-tls1_1" 315 | Disable TLS version 1.1 316 | .TP 317 | .BR " --no-tls1_3" 318 | Disable TLS version 1.3 319 | .TP 320 | .BR " --no-tls1_2" 321 | Disable TLS version 1.2 322 | .TP 323 | .BR " --not-issued-by" " issuer" 324 | Check that the issuer of the certificate does not match the given pattern 325 | .TP 326 | .BR " --not-valid-longer-than" " days" 327 | Critical if the certificate validity is longer than the specified period 328 | .TP 329 | .BR "-o,--org" " org" 330 | Pattern to match the organization of the certificate 331 | .TP 332 | .BR " --ocsp-critical" " hours" 333 | Minimum number of hours an OCSP response has to be valid to issue a critical status 334 | .TP 335 | .BR " --ocsp-warning" " hours" 336 | Minimum number of hours an OCSP response has to be valid to issue a warning status 337 | .TP 338 | .BR " --openssl" " path" 339 | Path of the openssl binary to be used 340 | .TP 341 | .BR "-p,--port" " port" 342 | TCP port (default 443) 343 | .TP 344 | .BR "--precision" " digits" 345 | Number of decimal places for durations: defaults to 0 if critical or warning are integers, 2 otherwise 346 | .TP 347 | .BR "-P,--protocol" " protocol" 348 | Use the specific protocol: dns, ftp, ftps, http, https (default), h2 (HTTP/2), h3 (HTTP/3), imap, imaps, irc, ircs, ldap, ldaps, mqtts, mysql, pop3, pop3s, postgres, sieve, sips, smtp, smtps, tds, xmpp, xmpp-server. ftp, imap, irc, ldap, pop3, postgres, sieve, smtp: switch to TLS using StartTLS. 349 | .BR 350 | These protocols switch to TLS using StartTLS: ftp, imap, irc, ldap, mysql, pop3, smtp. 351 | .TP 352 | .BR " --path" " path" 353 | Set the PATH variable to 'path' 354 | .TP 355 | .BR " --password" " source" 356 | Password source for a local certificate, see the PASS PHRASE ARGUMENTS section openssl(1) 357 | .TP 358 | .BR " --prometheus" 359 | Generate Prometheus/OpenMetrics output 360 | .TP 361 | .BR " --proxy" " proxy" 362 | Set http_proxy and the s_client -proxy option 363 | .TP 364 | .BR " --python-bin" " path" 365 | Path of the python binary to be used 366 | .TP 367 | .BR " --quic" 368 | Use QUIC 369 | .TP 370 | .BR "-q,--quiet" 371 | Do not produce any output 372 | .TP 373 | .BR "-r,--rootcert" " cert" 374 | Root certificate or directory to be used for certificate validation (passed to openssl's -CAfile or -CApath) 375 | .TP 376 | .BR " --require-client-cert" " [list]" 377 | The server must accept a client certificate. 'list' is an optional comma separated list of expected client certificate CAs 378 | .TP 379 | .BR " --require-dnssec" 380 | Require DNSSEC 381 | .TP 382 | .BR " --require-http-header" " header" 383 | Require the specified HTTP header (e.g., strict-transport-security) 384 | .TP 385 | .BR " --require-no-http-header" " header" 386 | Require the absence of the specified HTTP header (e.g., X-Powered-By) 387 | .TP 388 | .BR " --require-no-ssl2" 389 | Critical if SSL version 2 is offered 390 | .TP 391 | .BR " --require-no-ssl3" 392 | Critical if SSL version 3 is offered 393 | .TP 394 | .BR " --require-no-tls1" 395 | Critical if TLS 1 is offered 396 | .TP 397 | .BR " --require-no-tls1_1" 398 | Critical if TLS 1.1 is offered 399 | .TP 400 | .BR " --require-no-tls1_2" 401 | Critical if TLS 1.2 is offered 402 | .TP 403 | .BR " --require-ocsp-stapling" 404 | Require OCSP stapling 405 | .TP 406 | .BR " --require-purpose" " usage" 407 | Require the specified key usage (can be specified more then once) 408 | .TP 409 | .BR " --require-purpose-critical" 410 | The key usage must be critical 411 | .TP 412 | .BR " --require-security-header" " header" 413 | Require the specified HTTP security header (e.g., X-Frame-Options) 414 | .TP 415 | .BR " --require-security-headers" 416 | Require all the HTTP security headers: 417 | Content-Security-Policy 418 | Permissions-Policy 419 | Referrer-Policy 420 | strict-transport-security 421 | X-Content-Type-Options 422 | X-Frame-Options 423 | .TP 424 | .BR " --resolve" " ip" 425 | Provide a custom IP address for the specified host 426 | .TP 427 | .BR " --resolve-over-http" " [server]" 428 | Resolve the host over HTTP using Google or the specified server 429 | .TP 430 | .BR " --rootcert-dir" " dir" 431 | Root directory to be used for certificate validation (passed to openssl's -CApath) 432 | overrides option -r,--rootcert 433 | .TP 434 | .BR " --rootcert-file" " cert" 435 | Root certificate to be used for certificate validation (passed to openssl's -CAfile) 436 | overrides option -r,--rootcert 437 | .TP 438 | .BR " --rsa" 439 | Signature algorithm selection: force RSA certificate 440 | .TP 441 | .BR " --security-level" " number" 442 | Set the security level to specified value. See SSL_CTX_set_security_level(3) for a description of what each level means 443 | .TP 444 | .BR "-s,--selfsigned" 445 | Allow self-signed certificates 446 | .TP 447 | .BR " --serial" " serialnum" 448 | Pattern to match the serial number 449 | .TP 450 | .BR "--skip-element" " number" 451 | Skip checks on the Nth cert element (can be specified multiple times) 452 | .TP 453 | .BR " --sni" " name" 454 | Set the TLS SNI (Server Name Indication) extension in the ClientHello message to 'name' 455 | .TP 456 | .BR " --ssl2" 457 | Force SSL version 2 458 | .TP 459 | .BR " --ssl3" 460 | Force SSL version 3 461 | .TP 462 | .BR "-t,--timeout" " seconds" 463 | Timeout after the specified time (defaults to 120 seconds) 464 | .TP 465 | .BR " --temp" " dir" 466 | Directory where to store the temporary files 467 | .TP 468 | .BR " --terse" 469 | Terse output (also see --verbose) 470 | .TP 471 | .BR " --tls1" 472 | Force TLS version 1 473 | .TP 474 | .BR " --tls1_1" 475 | Force TLS version 1.1 476 | .TP 477 | .BR " --tls1_2" 478 | Force TLS version 1.2 479 | .TP 480 | .BR " --tls1_3" 481 | Force TLS version 1.3 482 | .TP 483 | .BR "-u,--url" " URL" 484 | HTTP request URL 485 | .TP 486 | .BR " --user-agent" " string" 487 | User agent that shall be used for HTTPS connections 488 | .TP 489 | .BR "-v,--verbose" 490 | Verbose output (can be specified more than once) 491 | .TP 492 | .BR "-V,--version" 493 | Version 494 | .TP 495 | .BR "-w,--warning" " days" 496 | Minimum number of days a certificate has to be valid to issue a warning status. Might be a floating point number, e.g., 0.5. Default: 20 497 | .TP 498 | .BR " --xmpphost" " name" 499 | Specify the host for the 'to' attribute of the stream element 500 | .TP 501 | .BR "-4" 502 | Force IPv4 503 | .TP 504 | .BR "-6" 505 | Force IPv6 506 | .SH DEPRECATED OPTIONS 507 | .TP 508 | .BR " --altnames" 509 | Match the pattern specified in -n with alternate names too (enabled by default) 510 | .TP 511 | .BR "-n,--cn" " name" 512 | Pattern to match the CN or AltName (can be specified multiple times) 513 | .TP 514 | .BR " --curl-user-agent" " string" 515 | User agent that curl shall use to obtain the issuer cert 516 | .TP 517 | .BR "-d,--days" " days" 518 | Minimum number of days a certificate has to be valid (see --critical and --warning) 519 | .TP 520 | .BR "-N,--host-cn" 521 | Match CN with the host name (enabled by default) 522 | .TP 523 | .BR " --no_ssl2" 524 | Disable SSLv2 (deprecated use --no-ssl2) 525 | .TP 526 | .BR " --no_ssl3" 527 | Disable SSLv3 (deprecated use --no-ssl3) 528 | .TP 529 | .BR " --no_tls1" 530 | Disable TLSv1 (deprecated use --no-tls1) 531 | .TP 532 | .BR " --no_tls1_1" 533 | Disable TLSv1.1 (deprecated use --no-tls1_1) 534 | .TP 535 | .BR " --no_tls1_2" 536 | Disable TLSv1.1 (deprecated use --no-tls1_2) 537 | .TP 538 | .BR " --no_tls1_3" 539 | Disable TLSv1.1 (deprecated use --no-tls1_3) 540 | .TP 541 | .BR " --ocsp" 542 | Check revocation via OCSP (enabled by default) 543 | .TP 544 | .BR " --require-hsts" 545 | Require HTTP Strict Transport Security (deprecated use --require-security-header strict-transport-security) 546 | .TP 547 | .BR " --require-security-headers-path" " path" 548 | the path to be used to fetch HTTP security headers 549 | .TP 550 | .BR " --require-san" 551 | Require the presence of a Subject Alternative Name extension 552 | .TP 553 | .BR " --require-x-frame-options [path]" 554 | Require the presence of the X-Frame-Options HTTP header. 'path' is the optional path to be used in the URL to check for the header (deprecated use --require-security-header X-Frame-Options and --require-security-headers-path path) 555 | .TP 556 | .BR "-S,--ssl" " version" 557 | Force SSL version (2,3) (see: --ssl2 or --ssl3) 558 | 559 | .SH CONFIGURATION 560 | 561 | Command line options can be specified in a configuration file (${HOME}/.check_ssl_certrc). For example 562 | 563 | $ cat ${HOME}/.check_ssl_certrc 564 | --verbose 565 | --critical 20 566 | --warning 40 567 | 568 | Options specified in the configuration file are read before processing the arguments and can be overridden. 569 | 570 | .SH NOTES 571 | If the host has multiple certificates and the installed openssl version supports the -servername option it is possible to specify the TLS SNI (Server Name Identificator) with the -N (or --host-cn) option. 572 | 573 | .SH "EXIT STATUS" 574 | check_ssl_cert returns a zero exist status if it finds no errors, 1 for warnings, 2 for a critical errors and 3 for unknown problems 575 | .SH BUGS 576 | Please report bugs to: 577 | https://github.com/matteocorti/check_ssl_cert/issues 578 | 579 | .SH "EXAMPLE" 580 | check_ssl_cert --host github.com --all-local 581 | 582 | .SH "SEE ALSO" 583 | openssl(1), openssl-x509(1) 584 | -------------------------------------------------------------------------------- /check_ssl_cert.completion: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | _check_ssl_cert() { 4 | 5 | local cur prev opts 6 | 7 | COMPREPLY=() 8 | 9 | cur="${COMP_WORDS[COMP_CWORD]}" 10 | prev="${COMP_WORDS[COMP_CWORD - 1]}" 11 | 12 | # 13 | # list of command line options 14 | # only the autocompletion with long options is implemented: long options are more readable and quick to enter since we are 15 | # using autocompletion. 16 | # 17 | opts="--file --host --noauth --all --all-local --allow-empty-san --clientcert --configuration --critical --check-chain --check-ciphers --check-ciphers-warnings --check-http-headers --check-ssl-labs --check-ssl-labs-warn --clientpass --crl --curl-bin --user-agent --custom-http-header --dane --date --debug-cert --debug-file --debug-headers --debug-time --default-format --dig-bin --do-not-resolve --dtls --dtls1 --dtls1_2 --ecdsa --element --file-bin --fingerprint --first-element-only --force-dconv-date --force-perl-date --format --grep-bin --http-headers-path --http-use-get --ignore-altnames --jks-alias --ignore-connection-problems --ignore-crl --ignore-exp --ignore-http-headers --ignore-host-cn --ignore-incomplete-chain --ignore-maximum-validity --ignore-ocsp --ignore-ocsp-errors --ignore-ocsp-timeout --ignore-sct --ignore-sig-alg --ignore-ssl-labs-cache --ignore-tls-renegotiation --ignore-unexpected-eof --inetproto protocol --info --init-host-cache --issuer-cert-cache --long-output --match --maximum-validity --nmap-bin --no-perf --no-proxy --no-proxy-curl --no-proxy-s_client --no-ssl2 --no-ssl3 --no-tls1 --no-tls1_1 --no-tls1_2 --no-tls1_3 --not-issued-by --not-valid-longer-than --ocsp-critical --ocsp-warning --openssl --password --path --precision --prometheus --proxy --require-client-cert --require-dnssec --require-http-header --require-no-http-header --require-no-ssl2 --require-no-ssl3 --require-no-tls1 --require-no-tls1_1 --require-no-tls1_2 --require-ocsp-stapling --require-purpose --require-purpose-critical --resolve --resolve-over-http --rootcert-dir --rootcert-file --rsa --serial --security-level --skip-element --sni --ssl2 --ssl3 --temp --terse --tls1 --tls1_1 --tls1_2 --tls1_3 --xmpphost -4 -6 --clientkey --protocol --version --debug --email --help --issuer --cn --org --port port --rootcert --quic --quiet --selfsigned --timeout --url --verbose --warning --python-bin" 18 | 19 | if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]]; then 20 | # shellcheck disable=2207 21 | COMPREPLY=($(compgen -W "${opts}" -- "${cur}")) 22 | return 0 23 | fi 24 | 25 | # 26 | # options with arguments: if the option requires an argument we try to autocomplete it if possible 27 | # 28 | case "${prev}" in 29 | 30 | # options with files or directories as argument 31 | -f | --file | -C | --clientcert | --configuration | --curl-bin | --date | --debug-file | --dig-bin | --file-bin | --grep-bin | --issuer-cert-cache | --nmap-bin | --openssl | --rootcert-dir | --rootcert-file | --temp | -K | --clientkey | -r | --rootcert | --python-bin) 32 | _filedir 33 | ;; 34 | 35 | # options with hosts as argument 36 | -H | --host | --resolve) 37 | _known_hosts_real "${cur}" 38 | if [[ -r ~/.check_ssl_cert-cache ]]; then 39 | # concatenate the array with the cached hosts: https://stackoverflow.com/questions/31143874/how-to-concatenate-arrays-in-bash 40 | # shellcheck disable=2207 41 | COMPREPLY+=($(compgen -W "$(tr <~/.check_ssl_cert-cache "\n" ' ')" -- "${cur}")) 42 | fi 43 | ;; 44 | 45 | # grades 46 | --check-ciphers | --check-ssl-labs-warn | --check-ssl-labs) 47 | # shellcheck disable=2207 48 | COMPREPLY=($(compgen -W "A B C D E F" -- "${cur}")) 49 | ;; 50 | 51 | --dane) 52 | # shellcheck disable=2207 53 | COMPREPLY=($(compgen -W "211 301 302 311 312" -- "${cur}")) 54 | ;; 55 | 56 | --maximum-validity) 57 | # shellcheck disable=2207 58 | COMPREPLY=($(compgen -W "397" -- "${cur}")) 59 | ;; 60 | 61 | --require-purpose) 62 | 63 | # the argument have spaces: see https://stackoverflow.com/questions/1146098/properly-handling-spaces-and-quotes-in-bash-completion 64 | 65 | # Get the currently completing word 66 | local CWORD=${COMP_WORDS[COMP_CWORD]} 67 | 68 | # This is our word list (in a bash array for convenience) 69 | local WORD_LIST=('Digital Signature' 'Key Encipherment' 'Key Agreement' 'Certificate Sign' 'Certificate Revocation List (CRL) Sign' 'CRL Sign') 70 | 71 | # Commands below depend on this IFS 72 | local IFS=$'\n' 73 | 74 | # Filter our candidates 75 | # shellcheck disable=2207 76 | CANDIDATES=($(compgen -W "${WORD_LIST[*]}" -- "$CWORD")) 77 | 78 | # Correctly set our candidates to COMPREPLY 79 | if [[ ${#CANDIDATES[*]} -eq 0 ]]; then 80 | COMPREPLY=() 81 | else 82 | # shellcheck disable=2207 83 | COMPREPLY=($(printf '%q\n' "${CANDIDATES[@]}")) 84 | fi 85 | ;; 86 | 87 | --require-http-header) 88 | 89 | # shellcheck disable=2207 90 | COMPREPLY=($(compgen -W "strict-transport-security X-Frame-Options Content-Security-Policy X-Content-Type-Options Referrer-Policy Permissions-Policy X-Permitted-Cross-Domain-Policies" -- "${cur}")) 91 | ;; 92 | 93 | --require-no-http-header) 94 | 95 | # shellcheck disable=2207 96 | COMPREPLY=($(compgen -W "X-Powered-By X-Aspnet-Version X-XSS-Protection Server X-AspNetMvc-Version" -- "${cur}")) 97 | ;; 98 | 99 | --security-level) 100 | 101 | # shellcheck disable=2207 102 | COMPREPLY=($(compgen -W "0 1 2 3 4 5" -- "${cur}")) 103 | ;; 104 | 105 | --port | -p) 106 | # shellcheck disable=2207 107 | COMPREPLY=($(compgen -W "21 22 80 443 143 993 194 994 389 587 636 3306 3391 110 995 5432 4190 25 465 5061 5222 5269" -- "${cur}")) 108 | ;; 109 | 110 | --protocol | -P) 111 | # shellcheck disable=2207 112 | COMPREPLY=($(compgen -W "dns ftp ftps http https h2 imap imaps irc ircs ldap ldaps mqtts mysql pop3 pop3s postgres sieve sips smtp smtps xmpp xmpp-server tds" -- "${cur}")) 113 | ;; 114 | 115 | *) ;; 116 | 117 | esac 118 | 119 | } 120 | 121 | complete -F _check_ssl_cert check_ssl_cert 122 | -------------------------------------------------------------------------------- /check_ssl_cert_icinga2.conf: -------------------------------------------------------------------------------- 1 | object CheckCommand "ssl_cert_extended" { 2 | import "plugin-check-command" 3 | 4 | command = [ PluginDir + "/check_ssl_cert.sh" ] 5 | 6 | arguments = { 7 | "--file" = { 8 | value = "$ssl_cert_extended_file$" 9 | description = "Local file path or URI. With -f you can not only pass a x509 certificate file but also a certificate revocation list (CRL) to check the validity period or a Java KeyStore file" 10 | } 11 | 12 | "--host" = { 13 | value = "$ssl_cert_extended_host$" 14 | description = "Server" 15 | } 16 | 17 | "--noauth" = { 18 | set_if = "$ssl_cert_extended_noauth$" 19 | description = "Ignore authority warnings (expiration only)" 20 | } 21 | 22 | "--all" = { 23 | set_if = "$ssl_cert_extended_all$" 24 | description = "Enable all the possible optional checks at the maximum level" 25 | } 26 | 27 | "--all-local" = { 28 | set_if = "$ssl_cert_extended_all_local$" 29 | description = "Enable all the possible optional checks at the maximum level (without SSL-Labs)" 30 | } 31 | 32 | "--allow-empty-san" = { 33 | set_if = "$ssl_cert_extended_allow_empty_san$" 34 | description = "Allow certificates without Subject Alternative Names (SANs)" 35 | } 36 | 37 | "--clientcert" = { 38 | value = "$ssl_cert_extended_clientcert$" 39 | description = "Use client certificate to authenticate" 40 | } 41 | 42 | "--critical" = { 43 | value = "$ssl_cert_extended_critical$" 44 | description = "Minimum number of days a certificate has to be valid to issue a critical status. Can be a floating point number, e.g., 0.5 Default: 15" 45 | } 46 | 47 | "--check-chain" = { 48 | set_if = "$ssl_cert_extended_check_chain$" 49 | description = "The certificate chain cannot contain double or root certificates" 50 | } 51 | 52 | "--check-ciphers" = { 53 | value = "$ssl_cert_extended_check_ciphers$" 54 | description = "Check the offered ciphers" 55 | } 56 | 57 | "--check-ciphers-warnings" = { 58 | set_if = "$ssl_cert_extended_check_ciphers_warnings$" 59 | description = "Critical if nmap reports a warning for an offered cipher" 60 | } 61 | 62 | "--check-http-headers" = { 63 | set_if = "$ssl_cert_extended_check_http_headers$" 64 | description = "Check the HTTP headers for best practices" 65 | } 66 | 67 | "--check-ssl-labs-warn" = { 68 | value = "$ssl_cert_extended_check_ssl_labs_warn$" 69 | description = "SSL Labs grade on which to warn" 70 | } 71 | 72 | "--clientpass" = { 73 | value = "$ssl_cert_extended_clientpass$" 74 | description = "Set passphrase for client certificate." 75 | } 76 | 77 | "--configuration" = { 78 | value = "$ssl_cert_extended_configuration$" 79 | description = "Read options from the specified file" 80 | } 81 | 82 | "--crl" = { 83 | set_if = "$ssl_cert_extended_crl$" 84 | description = "Check revocation via CRL (requires --rootcert-file)" 85 | } 86 | 87 | "--curl-bin" = { 88 | value = "$ssl_cert_extended_curl_bin$" 89 | description = "Path of the curl binary to be used" 90 | } 91 | 92 | "--custom-http-header" = { 93 | value = "$ssl_cert_extended_custom_http_header$" 94 | description = "Custom HTTP header sent when getting the cert example: 'X-Check-Ssl-Cert: Foobar=1'" 95 | } 96 | 97 | "--default-format" = { 98 | set_if = "$ssl_cert_extended_default_format$" 99 | description = "Print the default output format and exit" 100 | } 101 | 102 | "--dane" = { 103 | set_if = "$ssl_cert_extended_dane$" 104 | description = "Verify that valid DANE records exist (since OpenSSL 1.1.0)" 105 | } 106 | 107 | "--dane 211" = { 108 | set_if = "$ssl_cert_extended_dane_211$" 109 | description = "Verify that a valid DANE-TA(2) SPKI(1) SHA2-256(1) TLSA record exists" 110 | } 111 | 112 | "--dane 301" = { 113 | set_if = "$ssl_cert_extended_dane_301$" 114 | description = "Verify that a valid DANE-EE(3) Cert(0) SHA2-256(1) TLSA record exists" 115 | } 116 | 117 | "--dane 302" = { 118 | set_if = "$ssl_cert_extended_dane_302$" 119 | description = "Verify that a valid DANE-EE(3) Cert(0) SHA2-512(2) TLSA record exists" 120 | } 121 | 122 | "--dane 311" = { 123 | set_if = "$ssl_cert_extended_dane_311$" 124 | description = "Verify that a valid DANE-EE(3) SPKI(1) SHA2-256(1) TLSA record exists" 125 | } 126 | 127 | "--dane 312" = { 128 | set_if = "$ssl_cert_extended_dane_312$" 129 | description = "Verify that a valid DANE-EE(3) SPKI(1) SHA2-512(1) TLSA record exists" 130 | } 131 | 132 | "--date" = { 133 | set_if = "$ssl_cert_extended_date$" 134 | description = "Path of the date binary to be used" 135 | } 136 | 137 | "--debug" = { 138 | set_if = "$ssl_cert_extended_debug$" 139 | description = "Produce debugging output (can be specified more than once)" 140 | } 141 | 142 | "--debug-cert" = { 143 | set_if = "$ssl_cert_extended_debug_cert$" 144 | description = "Store the retrieved certificates in the current directory" 145 | } 146 | 147 | "--debug-headers" = { 148 | set_if = "$ssl_cert_extended_debug_headers$" 149 | description = "Store the retrieved HTLM headers in the headers.txt file" 150 | } 151 | 152 | "--debug-file" = { 153 | value = "$ssl_cert_extended_debug_file$" 154 | description = "Write the debug messages to file" 155 | } 156 | 157 | "--debug-time" = { 158 | set_if = "$ssl_cert_extended_debug_time$" 159 | description = "Write timing information in the debugging output" 160 | } 161 | 162 | "--dig-bin" = { 163 | value = "$ssl_cert_extended_dig_bin$" 164 | description = "Path of the dig binary to be used" 165 | } 166 | 167 | "--do-not-resolve" = { 168 | set_if = "$ssl_cert_extended_do_not_resolve$" 169 | description = "Do not check if the host can be resolved" 170 | } 171 | 172 | "--dtls" = { 173 | set_if = "$ssl_cert_extended_dtls$" 174 | description = "Use the DTLS protocol" 175 | } 176 | 177 | "--dtls1" = { 178 | set_if = "$ssl_cert_extended_dtls1$" 179 | description = "Use the DTLS protocol 1.0" 180 | } 181 | 182 | "--dtls1_2" = { 183 | set_if = "$ssl_cert_extended_dtls1_2$" 184 | description = "Use the DTLS protocol 1.2" 185 | } 186 | 187 | "--email" = { 188 | value = "$ssl_cert_extended_email$" 189 | description = "Pattern to match the email address contained in the certificate" 190 | } 191 | 192 | "--ecdsa" = { 193 | set_if = "$ssl_cert_extended_ecdsa$" 194 | description = "Signature algorithm selection: force ECDSA certificate" 195 | } 196 | 197 | "--element" = { 198 | value = "$ssl_cert_extended_element$" 199 | description = "Check up to the N cert element from the beginning of the chain" 200 | } 201 | 202 | "--file-bin" = { 203 | value = "$ssl_cert_extended_file_bin$" 204 | description = "Path of the file binary to be used" 205 | } 206 | 207 | "--fingerprint" = { 208 | value = "$ssl_cert_extended_fingerprint$" 209 | description = "Pattern to match the fingerprint" 210 | } 211 | 212 | "--fingerprint-alg" = { 213 | value = "$ssl_cert_extended_fingerprint_alg$" 214 | description = "Algorithm for fingerprint. Default sha1" 215 | } 216 | 217 | "--first-element-only" = { 218 | set_if = "$ssl_cert_extended_first_element_only$" 219 | description = "Verify just the first cert element, not the whole chain" 220 | } 221 | 222 | "--force-dconv-date" = { 223 | set_if = "$ssl_cert_extended_force_dconv_date$" 224 | description = "Force the usage of dconv for date computations" 225 | } 226 | 227 | "--force-perl-date" = { 228 | set_if = "$ssl_cert_extended_force_perl_date$" 229 | description = "Force the usage of dconv for date computations" 230 | } 231 | 232 | "--force-perl-date" = { 233 | set_if = "$ssl_cert_extended_force_perl_date$" 234 | description = "Force the usage of Perl for date computations" 235 | } 236 | 237 | "--format" = { 238 | value = "$ssl_cert_extended_format$" 239 | description = "Format output template on success, for example: '%SHORTNAME% OK %CN% from %CA_ISSUER_MATCHED%' list of possible variables: - %CA_ISSUER_MATCHED% - %CHECKEDNAMES% - %CN% - %DATE% - %DAYS_VALID% - %DYSPLAY_CN% - %HOST% - %OCSP_EXPIRES_IN_HOURS% - %OPENSSL_COMMAND% - %PORT% - %SELFSIGNEDCERT% - %SHORTNAME% - %SIGALGO% - %SSL_LABS_HOST_GRADE% See --default-format for the default" 240 | } 241 | 242 | "--grep-bin" = { 243 | value = "$ssl_cert_extended_grep_bin$" 244 | description = "Path of the grep binary to be used" 245 | } 246 | 247 | "--http-headers-path" = { 248 | value = "$ssl_cert_extended_http_headers_path$" 249 | description = "The path to be used to fetch HTTP headers" 250 | } 251 | 252 | "--http-use-get" = { 253 | set_if = "$ssl_cert_extended_http_use_get$" 254 | description = "Use GET instead of HEAD (default) for the HTTP related checks" 255 | } 256 | 257 | "--issuer" = { 258 | value = "$ssl_cert_extended_issuer$" 259 | description = "Pattern to match the issuer of the certificate" 260 | } 261 | 262 | "--ignore-altnames" = { 263 | set_if = "$ssl_cert_extended_ignore_altnames$" 264 | description = "Ignore alternative names when matching pattern specified in -n (or the host name)" 265 | } 266 | 267 | "--ignore-connection-problems" = { 268 | set_if = "$ssl_cert_extended_ignore_connection_problems$" 269 | description = "[state] In case of connection problems returns OK or the optional state" 270 | } 271 | 272 | "--ignore-crl" = { 273 | set_if = "$ssl_cert_extended_ignore_crl$" 274 | description = "[state] Ignore CRLs" 275 | } 276 | 277 | "--ignore-dh" = { 278 | set_if = "$ssl_cert_extended_ignore_dh$" 279 | description = "[state] Ignore too small DH keys" 280 | } 281 | 282 | "--ignore-exp" = { 283 | set_if = "$ssl_cert_extended_ignore_exp$" 284 | description = "Ignore expiration date" 285 | } 286 | 287 | "--ignore-http-headers" = { 288 | set_if = "$ssl_cert_extended_ignore_http_headers$" 289 | description = "Ignore checks on HTTP headers with --all and --all-local" 290 | } 291 | 292 | "--ignore-host-cn" = { 293 | set_if = "$ssl_cert_extended_ignore_host_cn$" 294 | description = "Do not complain if the CN does not match the host name" 295 | } 296 | 297 | "--ignore-incomplete-chain" = { 298 | set_if = "$ssl_cert_extended_ignore_incomplete_chain$" 299 | description = "Do not check chain integrity" 300 | } 301 | 302 | "--ignore-maximum-validity" = { 303 | set_if = "$ssl_cert_extended_ignore_maximum_validity$" 304 | description = "Ignore the certificate maximum validity" 305 | } 306 | 307 | "--ignore-ocsp" = { 308 | set_if = "$ssl_cert_extended_ignore_ocsp$" 309 | description = "Do not check revocation with OCSP" 310 | } 311 | 312 | "--ignore-ocsp-errors" = { 313 | set_if = "$ssl_cert_extended_ignore_ocsp_errors$" 314 | description = "Continue if the OCSP status cannot be checked" 315 | } 316 | 317 | "--ignore-ocsp-timeout" = { 318 | set_if = "$ssl_cert_extended_ignore_ocsp_timeout$" 319 | description = "Ignore OCSP result when timeout occurs while checking" 320 | } 321 | 322 | "--ignore-sct" = { 323 | set_if = "$ssl_cert_extended_ignore_sct$" 324 | description = "Do not check for signed certificate timestamps (SCT)" 325 | } 326 | 327 | "--ignore-sig-alg" = { 328 | set_if = "$ssl_cert_extended_ignore_sig_alg$" 329 | description = "Do not check if the certificate was signed with SHA1 or MD5" 330 | } 331 | 332 | "--ignore-ssl-labs-cache" = { 333 | set_if = "$ssl_cert_extended_ignore_ssl_labs_cache$" 334 | description = "Force a new check by SSL Labs (see -L)" 335 | } 336 | 337 | "--ignore-ssl-labs-errors" = { 338 | set_if = "$ssl_cert_extended_ignore_ssl_labs_errors$" 339 | description = "Ignore errors if SSL Labs is not accessible or times out" 340 | } 341 | 342 | "--ignore-tls-renegotiation" = { 343 | set_if = "$ssl_cert_extended_ignore_tls_renegotiation$" 344 | description = "Ignore the TLS renegotiation check" 345 | } 346 | 347 | "--ignore-unexpected-eof" = { 348 | set_if = "$ssl_cert_extended_ignore_unexpected_eof$" 349 | description = "Ignore unclean TLS shutdowns" 350 | } 351 | 352 | "--inetproto" = { 353 | value = "$ssl_cert_extended_inetproto$" 354 | description = "Force IP version 4 or 6" 355 | } 356 | 357 | "--info" = { 358 | set_if = "$ssl_cert_extended_info$" 359 | description = "Print certificate information" 360 | } 361 | 362 | "--init-host-cache" = { 363 | set_if = "$ssl_cert_extended_init_host_cache$" 364 | description = "Initialize the host cache" 365 | } 366 | 367 | "--issuer-cert-cache" = { 368 | value = "$ssl_cert_extended_issuer_cert_cache$" 369 | description = "Directory where to store issuer certificates cache" 370 | } 371 | 372 | "--jks-alias" = { 373 | value = "$ssl_cert_extended_jks_alias$" 374 | description = "Alias name of the Java KeyStore entry (requires --file)" 375 | } 376 | 377 | "--clientkey" = { 378 | value = "$ssl_cert_extended_clientkey$" 379 | description = "Use client certificate key to authenticate" 380 | } 381 | 382 | "--check-ssl-labs" = { 383 | value = "$ssl_cert_extended_check_ssl_labs$" 384 | description = "SSL Labs assessment (please check https://www.ssllabs.com/about/terms.html)" 385 | } 386 | 387 | "--long-output" = { 388 | value = "$ssl_cert_extended_long_output$" 389 | description = "Append the specified comma separated (no spaces) list of attributes to the plugin output on additional lines Valid attributes are: enddate, startdate, subject, issuer, modulus, serial, hash, email, ocsp_uri and fingerprint. 'all' will include all the available attributes." 390 | } 391 | 392 | "--match" = { 393 | value = "$ssl_cert_extended_match$" 394 | description = "Pattern to match the CN or AltName (can be specified multiple times)" 395 | } 396 | 397 | "--maximum-validity" = { 398 | value = "$ssl_cert_extended_maximum_validity$" 399 | description = "The maximum validity of the certificate must not exceed 'days' (default 397) This check is automatic for HTTPS" 400 | } 401 | 402 | "--nmap-bin" = { 403 | value = "$ssl_cert_extended_nmap_bin$" 404 | description = "Path of the nmap binary to be used" 405 | } 406 | 407 | "--nmap-with-proxy" = { 408 | value = "$ssl_cert_extended_nmap_with_proxy$" 409 | description = "Allow nmap to be used with a proxy" 410 | } 411 | 412 | "--no-perf" = { 413 | set_if = "$ssl_cert_extended_no_perf$" 414 | description = "Do not show performance data" 415 | } 416 | 417 | "--no-proxy" = { 418 | set_if = "$ssl_cert_extended_no_proxy$" 419 | description = "Ignore the http_proxy and https_proxy environment variables" 420 | } 421 | 422 | "--no-proxy-curl" = { 423 | set_if = "$ssl_cert_extended_no_proxy_curl$" 424 | description = "Ignore the http_proxy and https_proxy environment variables for curl" 425 | } 426 | 427 | "--no-proxy-s_client" = { 428 | set_if = "$ssl_cert_extended_no_proxy_s_client$" 429 | description = "Ignore the http_proxy and https_proxy environment variables for openssl s_client" 430 | } 431 | 432 | "--no-ssl2" = { 433 | set_if = "$ssl_cert_extended_no_ssl2$" 434 | description = "Disable SSL version 2" 435 | } 436 | 437 | "--no-ssl3" = { 438 | set_if = "$ssl_cert_extended_no_ssl3$" 439 | description = "Disable SSL version 3" 440 | } 441 | 442 | "--no-tls1" = { 443 | set_if = "$ssl_cert_extended_no_tls1$" 444 | description = "Disable TLS version 1" 445 | } 446 | 447 | "--no-tls1_1" = { 448 | set_if = "$ssl_cert_extended_no_tls1_1$" 449 | description = "Disable TLS version 1.1" 450 | } 451 | 452 | "--no-tls1_2" = { 453 | set_if = "$ssl_cert_extended_no_tls1_2$" 454 | description = "Disable TLS version 1.2" 455 | } 456 | 457 | "--no-tls1_3" = { 458 | set_if = "$ssl_cert_extended_no_tls1_3$" 459 | description = "Disable TLS version 1.3" 460 | } 461 | 462 | "--not-issued-by" = { 463 | value = "$ssl_cert_extended_not_issued_by$" 464 | description = "Check that the issuer of the certificate does not match the given pattern" 465 | } 466 | 467 | "--not-valid-longer-than" = { 468 | value = "$ssl_cert_extended_not_valid_longer_than$" 469 | description = "Critical if the certificate validity is longer than the specified period" 470 | } 471 | 472 | "--org" = { 473 | value = "$ssl_cert_extended_org$" 474 | description = "Pattern to match the organization of the certificate" 475 | } 476 | 477 | "--ocsp-critical" = { 478 | value = "$ssl_cert_extended_ocsp_critical$" 479 | description = "Minimum number of hours an OCSP response has to be valid to issue a critical status" 480 | } 481 | 482 | "--ocsp-warning" = { 483 | value = "$ssl_cert_extended_ocsp_warning$" 484 | description = "Minimum number of hours an OCSP response has to be valid to issue a warning status" 485 | } 486 | 487 | "--openssl" = { 488 | value = "$ssl_cert_extended_openssl$" 489 | description = "Path of the openssl binary to be used" 490 | } 491 | 492 | "--path" = { 493 | value = "$ssl_cert_extended_path$" 494 | description = "Set the PATH variable to 'path'" 495 | } 496 | 497 | "--port" = { 498 | value = "$ssl_cert_extended_port$" 499 | description = "TCP port (default 443)" 500 | } 501 | 502 | "--precision" = { 503 | value = "$ssl_cert_extended_precision$" 504 | description = "Number of decimal places for durations:defaults to 0 if critical or warning are integers, 2 otherwise" 505 | } 506 | 507 | "--protocol" = { 508 | value = "$ssl_cert_extended_protocol$" 509 | description = "Use the specific protocol: dns, ftp, ftps, http, https (default), h2 (HTTP/2), imap, imaps, irc, ircs, ldap, ldaps, mysql, pop3, pop3s, postgres, sieve, smtp, smtps, tds, xmpp, xmpp-server. ftp, imap, irc, ldap, pop3, postgres, sieve, smtp: switch to TLS using StartTLS" 510 | } 511 | 512 | "--password" = { 513 | value = "$ssl_cert_extended_password$" 514 | description = "Password source for a local certificate, see the PASS PHRASE ARGUMENTS section openssl(1)" 515 | } 516 | 517 | "--prometheus" = { 518 | set_if = "$ssl_cert_extended_prometheus$" 519 | description = "Generate Prometheus/OpenMetrics output" 520 | } 521 | 522 | "--proxy" = { 523 | value = "$ssl_cert_extended_proxy$" 524 | description = "Set http_proxy and the s_client -proxy option" 525 | } 526 | 527 | "--python-bin" = { 528 | value = "$ssl_cert_extended_python_bin$" 529 | description = "Path of the python binary to be used" 530 | } 531 | 532 | "--quic" = { 533 | set_if = "$ssl_cert_extended_quic$" 534 | description = "Use QUIC" 535 | } 536 | 537 | "--quiet" = { 538 | set_if = "$ssl_cert_extended_quiet$" 539 | description = "Do not produce any output" 540 | } 541 | 542 | "--rootcert" = { 543 | value = "$ssl_cert_extended_rootcert$" 544 | description = "Root certificate or directory to be used for certificate validation" 545 | } 546 | 547 | "--require-client-cert" = { 548 | value = "$ssl_cert_extended_require_client_cert$" 549 | description = "The server must accept a client certificate. 'list' is an optional comma separated list of expected client certificate CAs" 550 | } 551 | 552 | "--require-dnssec" = { 553 | set_if = "$ssl_cert_extended_require_dnssec$" 554 | description = "Require DNSSEC" 555 | } 556 | 557 | "--require-http-header" = { 558 | value = "$ssl_cert_extended_require_http_header$" 559 | description = "Require the specified HTTP header (e.g., X-Frame-Options)" 560 | } 561 | 562 | "--require-no-http-header" = { 563 | value = "$ssl_cert_extended_require_no_http_header$" 564 | description = "Require the absence of the specified HTTP header (e.g., X-Powered-By)" 565 | } 566 | 567 | "--require-no-ssl2" = { 568 | set_if = "$ssl_cert_extended_require_no_ssl2$" 569 | description = "Critical if SSL version 2 is offered" 570 | } 571 | 572 | "--require-no-ssl3" = { 573 | set_if = "$ssl_cert_extended_require_no_ssl3$" 574 | description = "Critical if SSL version 3 is offered" 575 | } 576 | 577 | "--require-no-tls1" = { 578 | set_if = "$ssl_cert_extended_require_no_tls1$" 579 | description = "Critical if TLS 1 is offered" 580 | } 581 | 582 | "--require-no-tls1_1" = { 583 | set_if = "$ssl_cert_extended_require_no_tls1_1$" 584 | description = "Critical if TLS 1.1 is offered" 585 | } 586 | 587 | "--require-no-tls1_2" = { 588 | set_if = "$ssl_cert_extended_require_no_tls1_2$" 589 | description = "Critical if TLS 1.2 is offered" 590 | } 591 | 592 | "--require-ocsp-stapling" = { 593 | set_if = "$ssl_cert_extended_require_ocsp_stapling$" 594 | description = "Require OCSP stapling" 595 | } 596 | 597 | "--require-purpose" = { 598 | value = "$ssl_cert_extended_require_purpose$" 599 | description = "Require the specified key usage (can be specified more then once)" 600 | } 601 | 602 | "--require-purpose-critical" = { 603 | set_if = "$ssl_cert_extended_require_purpose_critical$" 604 | description = "The key usage must be critical" 605 | } 606 | 607 | "--resolve" = { 608 | value = "$ssl_cert_extended_resolve$" 609 | description = "Provide a custom IP address for the specified host" 610 | } 611 | 612 | "--resolve-over-http" = { 613 | value = "$ssl_cert_extended_resolve_over_http$" 614 | description = "Resolve the host over HTTP using Google or the specified server" 615 | } 616 | 617 | "--rootcert-dir" = { 618 | value = "$ssl_cert_extended_rootcert_dir$" 619 | description = "Root directory to be used for certificate validation" 620 | } 621 | 622 | "--rootcert-file" = { 623 | value = "$ssl_cert_extended_rootcert_file$" 624 | description = "Root certificate to be used for certificate validation" 625 | } 626 | 627 | "--rsa" = { 628 | set_if = "$ssl_cert_extended_rsa$" 629 | description = "Signature algorithm selection: force RSA certificate" 630 | } 631 | 632 | "--security-level" = { 633 | value = "$ssl_cert_extended_security_level$" 634 | description = "Set the security level to specified value See SSL_CTX_set_security_level(3) for a description of what each level means" 635 | } 636 | 637 | "--selfsigned" = { 638 | set_if = "$ssl_cert_extended_selfsigned$" 639 | description = "Allow self-signed certificates" 640 | } 641 | 642 | "--serial" = { 643 | value = "$ssl_cert_extended_serial$" 644 | description = "Pattern to match the serial number" 645 | } 646 | 647 | "--skip-element" = { 648 | value = "$ssl_cert_extended_skip_element$" 649 | description = "Skip checks on the Nth cert element (can be specified multiple times)" 650 | } 651 | 652 | "--sni" = { 653 | value = "$ssl_cert_extended_sni$" 654 | description = "Set the TLS SNI (Server Name Indication) extension in the ClientHello message to 'name'" 655 | } 656 | 657 | "--ssl2" = { 658 | set_if = "$ssl_cert_extended_ssl2$" 659 | description = "Force SSL version 2" 660 | } 661 | 662 | "--ssl3" = { 663 | set_if = "$ssl_cert_extended_ssl3$" 664 | description = "Force SSL version 3" 665 | } 666 | 667 | "--timeout" = { 668 | value = "$ssl_cert_extended_timeout$" 669 | description = "Timeout after the specified time (defaults to 120 seconds)" 670 | } 671 | 672 | "--temp" = { 673 | value = "$ssl_cert_extended_temp$" 674 | description = "Directory where to store the temporary files" 675 | } 676 | 677 | "--terse" = { 678 | set_if = "$ssl_cert_extended_terse$" 679 | description = "Terse output" 680 | } 681 | 682 | "--tls1" = { 683 | set_if = "$ssl_cert_extended_tls1$" 684 | description = "Force TLS version 1" 685 | } 686 | 687 | "--tls1_1" = { 688 | set_if = "$ssl_cert_extended_tls1_1$" 689 | description = "Force TLS version 1.1" 690 | } 691 | 692 | "--tls1_2" = { 693 | set_if = "$ssl_cert_extended_tls1_2$" 694 | description = "Force TLS version 1.2" 695 | } 696 | 697 | "--tls1_3" = { 698 | set_if = "$ssl_cert_extended_tls1_3$" 699 | description = "Force TLS version 1.3" 700 | } 701 | 702 | "--url" = { 703 | value = "$ssl_cert_extended_url$" 704 | description = "HTTP request URL" 705 | } 706 | 707 | "--user-agent" = { 708 | value = "$ssl_cert_extended_user_agent$" 709 | description = "User agent that shall be used for HTTPS connections" 710 | } 711 | 712 | "--verbose" = { 713 | set_if = "$ssl_cert_extended_verbose$" 714 | description = "Verbose output (can be specified more than once)" 715 | } 716 | 717 | "--warning" = { 718 | value = "$ssl_cert_extended_warning$" 719 | description = "Minimum number of days a certificate has to be valid to issue a warning status. Can be a floating point number, e.g., 0.5 Default: 20" 720 | } 721 | 722 | "--xmpphost" = { 723 | value = "$ssl_cert_extended_xmpphost$" 724 | description = " Specify the host for the 'to' attribute of the stream element" 725 | } 726 | 727 | "-4" = { 728 | set_if = "$ssl_cert_extended_4$" 729 | description = "Force IPv4" 730 | } 731 | 732 | "-6" = { 733 | set_if = "$ssl_cert_extended_6$" 734 | description = "Force IPv6" 735 | } 736 | } 737 | 738 | vars.ssl_cert_extended_warning = 30 739 | vars.ssl_cert_extended_critical = 14 740 | vars.ssl_cert_extended_require_no_ssl2 = true 741 | vars.ssl_cert_extended_require_no_ssl3 = true 742 | vars.ssl_cert_extended_require_no_tls1 = true 743 | vars.ssl_cert_extended_require_no_tls1_1 = true 744 | } 745 | -------------------------------------------------------------------------------- /pull_request_template.md: -------------------------------------------------------------------------------- 1 | Fixes # 2 | 3 | ## Proposed Changes 4 | 5 | - 6 | - 7 | - 8 | -------------------------------------------------------------------------------- /test/badssl_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SSL_LABS_HOST=ethz.ch 4 | 5 | # $SHUNIT2 should be defined as an environment variable before running the tests 6 | # shellcheck disable=SC2154 7 | if [ -z "${SHUNIT2}" ]; then 8 | 9 | SHUNIT2=$(command -v shunit2) 10 | 11 | if [ -z "${SHUNIT2}" ]; then 12 | 13 | cat < /dev/null 2>&1 46 | TINYPROXY=$! 47 | } 48 | 49 | stopLocalProxy() { 50 | if [ -n "${TINYPROXY}" ] ; then 51 | kill "${TINYPROXY}" 52 | fi 53 | } 54 | 55 | oneTimeSetUp() { 56 | # constants 57 | 58 | NAGIOS_OK=0 59 | NAGIOS_CRITICAL=2 60 | 61 | COUNTER=1 62 | START_TIME=$(date +%s) 63 | 64 | if [ -z "${TMPDIR}" ]; then 65 | TMPDIR=/tmp 66 | fi 67 | 68 | # Cleanup before program termination 69 | # Using named signals to be POSIX compliant 70 | # shellcheck disable=SC2086 71 | trap_with_arg cleanup ${SIGNALS} 72 | 73 | # we trigger a test by Qualy's SSL so that when the last test is run the result will be cached 74 | # echo 'Starting SSL Lab test (to cache the result)' 75 | # curl --silent "https://www.ssllabs.com/ssltest/analyze.html?d=${SSL_LABS_HOST}&latest" >/dev/null 76 | 77 | # print the openssl version 78 | echo 'OpenSSL version' 79 | if [ -z "${OPENSSL}" ]; then 80 | OPENSSL=$(command -v openssl) # needed by openssl_version 81 | fi 82 | "${OPENSSL}" version 83 | 84 | if [ -z "${GREP_BIN}" ]; then 85 | GREP_BIN=$(command -v grep) # needed by openssl_version 86 | fi 87 | if ! "${GREP_BIN}" -V >/dev/null 2>&1; then 88 | echo "Cannot determine grep version (Busybox?)" 89 | else 90 | "${GREP_BIN}" -V 91 | fi 92 | 93 | true # if the last variable is empty the setup will fail 94 | 95 | } 96 | 97 | seconds2String() { 98 | seconds=$1 99 | if [ "${seconds}" -gt 60 ]; then 100 | minutes=$((seconds / 60)) 101 | seconds=$((seconds % 60)) 102 | if [ "${minutes}" -gt 1 ]; then 103 | MINUTE_S="minutes" 104 | else 105 | MINUTE_S="minute" 106 | fi 107 | if [ "${seconds}" -eq 1 ]; then 108 | SECOND_S=" and ${seconds} second" 109 | elif [ "${seconds}" -eq 0 ]; then 110 | SECOND_S= 111 | else 112 | SECOND_S=" and ${seconds} seconds" 113 | fi 114 | string="${minutes} ${MINUTE_S}${SECOND_S}" 115 | else 116 | if [ "${seconds}" -eq 1 ]; then 117 | SECOND_S="second" 118 | else 119 | SECOND_S="seconds" 120 | fi 121 | string="${seconds} ${SECOND_S}" 122 | fi 123 | echo "${string}" 124 | 125 | } 126 | 127 | oneTimeTearDown() { 128 | 129 | NOW=$(date +%s) 130 | ELAPSED=$((NOW - START_TIME)) 131 | # shellcheck disable=SC2154 132 | ELAPSED_STRING=$(seconds2String "${ELAPSED}") 133 | echo 134 | echo "Total time: ${ELAPSED_STRING}" 135 | } 136 | 137 | setUp() { 138 | echo 139 | 140 | # shellcheck disable=SC2154 141 | PERCENT=$(echo "scale=2; ${COUNTER} / ${__shunit_testsTotal} * 100" | bc | sed 's/[.].*//') 142 | 143 | NOW=$(date +%s) 144 | ELAPSED=$((NOW - START_TIME)) 145 | # shellcheck disable=SC2154 146 | REMAINING_S=$(echo "scale=2; ${__shunit_testsTotal} * ( ${ELAPSED} ) / ${COUNTER} - ${ELAPSED}" | bc | sed 's/[.].*//') 147 | if [ -z "${REMAINING_S}" ]; then 148 | REMAINING_S=0 149 | fi 150 | REMAINING=$(seconds2String "${REMAINING_S}") 151 | 152 | if [ -n "${http_proxy}" ]; then 153 | # print the test number 154 | # shellcheck disable=SC2154 155 | echo "Running test ${COUNTER} (proxy=${http_proxy}) of ${__shunit_testsTotal} (${PERCENT}%), ${REMAINING} remaining (${__shunit_testsFailed} failed, ${__shunit_assertsSkipped} skipped)" 156 | else 157 | # print the test number 158 | # shellcheck disable=SC2154 159 | echo "Running test ${COUNTER} of ${__shunit_testsTotal} (${PERCENT}%), ${REMAINING} remaining (${__shunit_testsFailed} failed, ${__shunit_assertsSkipped} skipped)" 160 | fi 161 | COUNTER=$((COUNTER + 1)) 162 | } 163 | 164 | ############################################################################## 165 | # Tests 166 | 167 | testSignatureAlgorithms() { 168 | 169 | echo " testing sha256WithRSAEncryption (2048 bit)" 170 | # shellcheck disable=SC2086 171 | ALGORITHM=$(${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt --info --ignore-exp --host rsa2048.badssl.com | 172 | grep '^Signature algorithm' | 173 | sed 's/^Signature algorithm *//') 174 | assertEquals "wrong signature algorithm" 'sha256WithRSAEncryption (2048 bit)' "${ALGORITHM}" 175 | 176 | echo " testing sha256WithRSAEncryption (4096 bit)" 177 | # shellcheck disable=SC2086 178 | ALGORITHM=$(${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt --info --ignore-exp --host rsa4096.badssl.com | 179 | grep '^Signature algorithm' | 180 | sed 's/^Signature algorithm *//') 181 | assertEquals "wrong signature algorithm" 'sha256WithRSAEncryption (4096 bit)' "${ALGORITHM}" 182 | 183 | echo " testing sha256WithRSAEncryption (8192 bit)" 184 | # shellcheck disable=SC2086 185 | ALGORITHM=$(${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt --info --ignore-exp --host rsa8192.badssl.com | 186 | grep '^Signature algorithm' | 187 | sed 's/^Signature algorithm *//') 188 | assertEquals "wrong signature algorithm" 'sha256WithRSAEncryption (8192 bit)' "${ALGORITHM}" 189 | 190 | } 191 | 192 | testSCT() { 193 | if [ -z "${OPENSSL}" ]; then 194 | OPENSSL=$(command -v openssl) # needed by openssl_version 195 | fi 196 | ${OPENSSL} version 197 | if openssl_version '1.1.0'; then 198 | echo "OpenSSL >= 1.1.0: SCTs supported" 199 | # shellcheck disable=SC2086 200 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -H no-sct.badssl.com --ignore-exp 201 | EXIT_CODE=$? 202 | assertEquals "wrong exit code" "${NAGIOS_CRITICAL}" "${EXIT_CODE}" 203 | else 204 | echo "OpenSSL < 1.1.0: SCTs not supported" 205 | # shellcheck disable=SC2086 206 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -H no-sct.badssl.com --ignore-exp 207 | EXIT_CODE=$? 208 | assertEquals "wrong exit code" "${NAGIOS_OK}" "${EXIT_CODE}" 209 | fi 210 | } 211 | 212 | testBadSSLExpired() { 213 | host=expired.badssl.com 214 | if ! nmap --unprivileged -Pn -p 443 "${host}" | grep -q '^443.*open' ; then 215 | startSkipping 216 | echo "Skipping test: cannot connect to ${host}:443" 217 | fi 218 | # shellcheck disable=SC2086 219 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -H "${host}" 220 | EXIT_CODE=$? 221 | assertEquals "wrong exit code" "${NAGIOS_CRITICAL}" "${EXIT_CODE}" 222 | } 223 | 224 | testBadSSLExpiredAndWarnThreshold() { 225 | host=expired.badssl.com 226 | if ! nmap --unprivileged -Pn -p 443 "${host}" | grep -q '^443.*open' ; then 227 | startSkipping 228 | echo "Skipping test: cannot connect to ${host}:443" 229 | fi 230 | # shellcheck disable=SC2086 231 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -H "${host}" --warning 3000 232 | EXIT_CODE=$? 233 | assertEquals "wrong exit code" "${NAGIOS_CRITICAL}" "${EXIT_CODE}" 234 | } 235 | 236 | testBadSSLWrongHost() { 237 | host=wrong.host.badssl.com 238 | if ! nmap --unprivileged -Pn -p 443 "${host}" | grep -q '^443.*open' ; then 239 | startSkipping 240 | echo "Skipping test: cannot connect to ${host}:443" 241 | fi 242 | # shellcheck disable=SC2086 243 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -H "${host}" --ignore-exp 244 | EXIT_CODE=$? 245 | assertEquals "wrong exit code" "${NAGIOS_CRITICAL}" "${EXIT_CODE}" 246 | } 247 | 248 | testBadSSLSelfSigned() { 249 | host=self-signed.badssl.com 250 | if ! nmap --unprivileged -Pn -p 443 "${host}" | grep -q '^443.*open' ; then 251 | startSkipping 252 | echo "Skipping test: cannot connect to ${host}:443" 253 | fi 254 | # shellcheck disable=SC2086 255 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -H "${host}" --ignore-exp 256 | EXIT_CODE=$? 257 | assertEquals "wrong exit code" "${NAGIOS_CRITICAL}" "${EXIT_CODE}" 258 | } 259 | 260 | testBadSSLUntrustedRoot() { 261 | host=untrusted-root.badssl.com 262 | if ! nmap --unprivileged -Pn -p 443 "${host}" | grep -q '^443.*open' ; then 263 | startSkipping 264 | echo "Skipping test: cannot connect to ${host}:443" 265 | fi 266 | # shellcheck disable=SC2086 267 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -H "${host}" --ignore-exp 268 | EXIT_CODE=$? 269 | assertEquals "wrong exit code" "${NAGIOS_CRITICAL}" "${EXIT_CODE}" 270 | } 271 | 272 | testBadSSLRevoked() { 273 | host=revoked.badssl.com 274 | if ! nmap --unprivileged -Pn -p 443 "${host}" | grep -q '^443.*open' ; then 275 | startSkipping 276 | echo "Skipping test: cannot connect to ${host}:443" 277 | fi 278 | # shellcheck disable=SC2086 279 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -H "${host}" 280 | EXIT_CODE=$? 281 | assertEquals "wrong exit code" "${NAGIOS_CRITICAL}" "${EXIT_CODE}" 282 | } 283 | 284 | testGRCRevoked() { 285 | host=revoked.grc.com 286 | if ! nmap --unprivileged -Pn -p 443 "${host}" | grep -q '^443.*open' ; then 287 | startSkipping 288 | echo "Skipping test: cannot connect to ${host}:443" 289 | fi 290 | # shellcheck disable=SC2086 291 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -H "${host}" 292 | EXIT_CODE=$? 293 | assertEquals "wrong exit code" "${NAGIOS_CRITICAL}" "${EXIT_CODE}" 294 | } 295 | 296 | testBadSSLIncompleteChain() { 297 | host=incomplete-chain.badssl.com 298 | if ! nmap --unprivileged -Pn -p 443 "${host}" | grep -q '^443.*open' ; then 299 | startSkipping 300 | echo "Skipping test: cannot connect to ${host}:443" 301 | fi 302 | # shellcheck disable=SC2086 303 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -H "${host}" 304 | EXIT_CODE=$? 305 | assertEquals "wrong exit code" "${NAGIOS_CRITICAL}" "${EXIT_CODE}" 306 | } 307 | 308 | testBadSSLDH480() { 309 | host=dh480.badssl.com 310 | if ! nmap --unprivileged -Pn -p 443 "${host}" | grep -q '^443.*open' ; then 311 | startSkipping 312 | echo "Skipping test: cannot connect to ${host}:443" 313 | fi 314 | # shellcheck disable=SC2086 315 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -H "${host}" --ignore-exp 316 | EXIT_CODE=$? 317 | assertEquals "wrong exit code" "${NAGIOS_CRITICAL}" "${EXIT_CODE}" 318 | } 319 | 320 | testBadSSLDH512() { 321 | host=dh512.badssl.com 322 | if ! nmap --unprivileged -Pn -p 443 "${host}" | grep -q '^443.*open' ; then 323 | startSkipping 324 | echo "Skipping test: cannot connect to ${host}:443" 325 | fi 326 | # shellcheck disable=SC2086 327 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -H "${host}" --ignore-exp 328 | EXIT_CODE=$? 329 | assertEquals "wrong exit code" "${NAGIOS_CRITICAL}" "${EXIT_CODE}" 330 | } 331 | 332 | testBadSSLRC4MD5() { 333 | host=rc4-md5.badssl.com 334 | if ! nmap --unprivileged -Pn -p 443 "${host}" | grep -q '^443.*open' ; then 335 | startSkipping 336 | echo "Skipping test: cannot connect to ${host}:443" 337 | fi 338 | # older versions of OpenSSL validate RC4-MD5 339 | if "${OPENSSL}" ciphers RC4-MD5 >/dev/null 2>&1; then 340 | startSkipping 341 | echo "Skipping test: OpenSSL too old to test RC4-MD5 ciphers" 342 | fi 343 | # shellcheck disable=SC2086 344 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -H "${host}" --ignore-exp 345 | EXIT_CODE=$? 346 | assertEquals "wrong exit code" "${NAGIOS_CRITICAL}" "${EXIT_CODE}" 347 | } 348 | 349 | 350 | testBadSSLRC4() { 351 | host=rc4.badssl.com 352 | if ! nmap --unprivileged -Pn -p 443 "${host}" | grep -q '^443.*open' ; then 353 | startSkipping 354 | echo "Skipping test: cannot connect to ${host}:443" 355 | fi 356 | # older versions of OpenSSL validate RC4 357 | if "${OPENSSL}" ciphers RC4 >/dev/null 2>&1; then 358 | startSkipping 359 | fi 360 | # shellcheck disable=SC2086 361 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -H "${host}" --ignore-exp 362 | EXIT_CODE=$? 363 | assertEquals "wrong exit code" "${NAGIOS_CRITICAL}" "${EXIT_CODE}" 364 | } 365 | 366 | testBadSSL3DES() { 367 | host=3des.badssl.com 368 | if ! nmap --unprivileged -Pn -p 443 "${host}" | grep -q '^443.*open' ; then 369 | startSkipping 370 | echo "Skipping test: cannot connect to ${host}:443" 371 | fi 372 | # older versions of OpenSSL validate RC4 373 | if "${OPENSSL}" ciphers 3DES >/dev/null 2>&1; then 374 | startSkipping 375 | echo "Skipping test: OpenSSL too old to test 3DES ciphers" 376 | fi 377 | # shellcheck disable=SC2086 378 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -H "${host}" --ignore-exp 379 | EXIT_CODE=$? 380 | assertEquals "wrong exit code" "${NAGIOS_CRITICAL}" "${EXIT_CODE}" 381 | } 382 | 383 | testBadSSLNULL() { 384 | host=null.badssl.com 385 | if ! nmap --unprivileged -Pn -p 443 "${host}" | grep -q '^443.*open' ; then 386 | startSkipping 387 | echo "Skipping test: cannot connect to ${host}:443" 388 | fi 389 | # shellcheck disable=SC2086 390 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -H "${host}" --ignore-exp 391 | EXIT_CODE=$? 392 | assertEquals "wrong exit code" "${NAGIOS_CRITICAL}" "${EXIT_CODE}" 393 | } 394 | 395 | testBadSSLSHA256() { 396 | host=sha256.badssl.com 397 | if ! nmap --unprivileged -Pn -p 443 "${host}" | grep -q '^443.*open' ; then 398 | startSkipping 399 | echo "Skipping test: cannot connect to ${host}:443" 400 | fi 401 | # shellcheck disable=SC2086 402 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -H "${host}" --ignore-exp 403 | EXIT_CODE=$? 404 | assertEquals "wrong exit code" "${NAGIOS_OK}" "${EXIT_CODE}" 405 | } 406 | 407 | testBadSSLEcc256() { 408 | host=ecc256.badssl.com 409 | if ! nmap --unprivileged -Pn -p 443 "${host}" | grep -q '^443.*open' ; then 410 | startSkipping 411 | echo "Skipping test: cannot connect to ${host}:443" 412 | fi 413 | # shellcheck disable=SC2086 414 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -H "${host}" --ignore-exp 415 | EXIT_CODE=$? 416 | assertEquals "wrong exit code" "${NAGIOS_OK}" "${EXIT_CODE}" 417 | } 418 | 419 | testBadSSLEcc384() { 420 | host=ecc384.badssl.com 421 | if ! nmap --unprivileged -Pn -p 443 "${host}" | grep -q '^443.*open' ; then 422 | startSkipping 423 | echo "Skipping test: cannot connect to ${host}:443" 424 | fi 425 | # shellcheck disable=SC2086 426 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -H "${host}" --ignore-exp 427 | EXIT_CODE=$? 428 | assertEquals "wrong exit code" "${NAGIOS_OK}" "${EXIT_CODE}" 429 | } 430 | 431 | testBadSSLRSA8192() { 432 | host=rsa8192.badssl.com 433 | if ! nmap --unprivileged -Pn -p 443 "${host}" | grep -q '^443.*open' ; then 434 | startSkipping 435 | echo "Skipping test: cannot connect to ${host}:443" 436 | fi 437 | # shellcheck disable=SC2086 438 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -H "${host}" --ignore-exp 439 | EXIT_CODE=$? 440 | assertEquals "wrong exit code" "${NAGIOS_OK}" "${EXIT_CODE}" 441 | } 442 | 443 | testBadSSLLongSubdomainWithDashes() { 444 | host=long-extended-subdomain-name-containing-many-letters-and-dashes.badssl.com 445 | if ! nmap --unprivileged -Pn -p 443 "${host}" | grep -q '^443.*open' ; then 446 | startSkipping 447 | echo "Skipping test: cannot connect to ${host}:443" 448 | fi 449 | # shellcheck disable=SC2086 450 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -H "${host}" --ignore-exp 451 | EXIT_CODE=$? 452 | assertEquals "wrong exit code" "${NAGIOS_OK}" "${EXIT_CODE}" 453 | } 454 | 455 | testBadSSLLongSubdomain() { 456 | host=longextendedsubdomainnamewithoutdashesinordertotestwordwrapping.badssl.com 457 | if ! nmap --unprivileged -Pn -p 443 "${host}" | grep -q '^443.*open' ; then 458 | startSkipping 459 | echo "Skipping test: cannot connect to ${host}:443" 460 | fi 461 | # shellcheck disable=SC2086 462 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -H "${host}" --ignore-exp 463 | EXIT_CODE=$? 464 | assertEquals "wrong exit code" "${NAGIOS_OK}" "${EXIT_CODE}" 465 | } 466 | 467 | testBadSSLSHA12016() { 468 | host=sha1-2016.badssl.com 469 | if ! nmap --unprivileged -Pn -p 443 "${host}" | grep -q '^443.*open' ; then 470 | startSkipping 471 | echo "Skipping test: cannot connect to ${host}:443" 472 | fi 473 | # shellcheck disable=SC2086 474 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -H "${host}" --ignore-exp 475 | EXIT_CODE=$? 476 | assertEquals "wrong exit code" "${NAGIOS_CRITICAL}" "${EXIT_CODE}" 477 | } 478 | 479 | testBadSSLSHA12017() { 480 | host=sha1-2017.badssl.com 481 | if ! nmap --unprivileged -Pn -p 443 "${host}" | grep -q '^443.*open' ; then 482 | startSkipping 483 | echo "Skipping test: cannot connect to ${host}:443" 484 | fi 485 | # shellcheck disable=SC2086 486 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -H "${host}" --ignore-exp 487 | EXIT_CODE=$? 488 | assertEquals "wrong exit code" "${NAGIOS_CRITICAL}" "${EXIT_CODE}" 489 | } 490 | 491 | testXFrameOptionsFailed() { 492 | # shellcheck disable=SC2086 493 | ${SCRIPT} ${TEST_DEBUG} -H badssl.com --ignore-exp --require-http-header X-Frame-Options 494 | EXIT_CODE=$? 495 | assertEquals "wrong exit code" "${NAGIOS_CRITICAL}" "${EXIT_CODE}" 496 | } 497 | 498 | testHTTPHeadersFailed() { 499 | # shellcheck disable=SC2086 500 | ${SCRIPT} ${TEST_DEBUG} -H badssl.com --ignore-exp --require-security-headers 501 | EXIT_CODE=$? 502 | assertEquals "wrong exit code" "${NAGIOS_CRITICAL}" "${EXIT_CODE}" 503 | } 504 | 505 | testHTTPHeaderFailed() { 506 | # shellcheck disable=SC2086 507 | ${SCRIPT} ${TEST_DEBUG} -H badssl.com --ignore-exp --require-http-header X-Frame-Options --require-http-header x-xss-protection 508 | EXIT_CODE=$? 509 | assertEquals "wrong exit code" "${NAGIOS_CRITICAL}" "${EXIT_CODE}" 510 | } 511 | 512 | testWrongHost() { 513 | # shellcheck disable=SC2086 514 | ${SCRIPT} ${TEST_DEBUG} --host wrong.host.badssl.com --ignore-exp 515 | EXIT_CODE=$? 516 | assertEquals "wrong exit code" "${NAGIOS_CRITICAL}" "${EXIT_CODE}" 517 | } 518 | 519 | testWrongHostIgnore() { 520 | # shellcheck disable=SC2086 521 | ${SCRIPT} ${TEST_DEBUG} --host wrong.host.badssl.com --ignore-host-cn --ignore-exp 522 | EXIT_CODE=$? 523 | assertEquals "wrong exit code" "${NAGIOS_OK}" "${EXIT_CODE}" 524 | } 525 | 526 | # the script will exit without executing main 527 | export SOURCE_ONLY='test' 528 | 529 | # source the script. 530 | # Do not follow 531 | # shellcheck disable=SC1090 532 | . "${SCRIPT}" 533 | 534 | unset SOURCE_ONLY 535 | 536 | # run shUnit: it will execute all the tests in this file 537 | # (e.g., functions beginning with 'test' 538 | # 539 | # We clone to output to pass it to grep as shunit does always return 0 540 | # We parse the output to check if a test failed 541 | # 542 | 543 | # Do not follow 544 | # shellcheck disable=SC1090 545 | . "${SHUNIT2}" 546 | -------------------------------------------------------------------------------- /test/cacert.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIHWTCCBUGgAwIBAgIDCkGKMA0GCSqGSIb3DQEBCwUAMHkxEDAOBgNVBAoTB1Jv 3 | b3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEiMCAGA1UEAxMZ 4 | Q0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYSc3VwcG9y 5 | dEBjYWNlcnQub3JnMB4XDTExMDUyMzE3NDgwMloXDTIxMDUyMDE3NDgwMlowVDEU 6 | MBIGA1UEChMLQ0FjZXJ0IEluYy4xHjAcBgNVBAsTFWh0dHA6Ly93d3cuQ0FjZXJ0 7 | Lm9yZzEcMBoGA1UEAxMTQ0FjZXJ0IENsYXNzIDMgUm9vdDCCAiIwDQYJKoZIhvcN 8 | AQEBBQADggIPADCCAgoCggIBAKtJNRFIfNImflOUz0Op3SjXQiqL84d4GVh8D57a 9 | iX3h++tykA10oZZkq5+gJJlz2uJVdscXe/UErEa4w75/ZI0QbCTzYZzA8pD6Ueb1 10 | aQFjww9W4kpCz+JEjCUoqMV5CX1GuYrz6fM0KQhF5Byfy5QEHIGoFLOYZcRD7E6C 11 | jQnRvapbjZLQ7N6QxX8KwuPr5jFaXnQ+lzNZ6MMDPWAzv/fRb0fEze5ig1JuLgia 12 | pNkVGJGmhZJHsK5I6223IeyFGmhyNav/8BBdwPSUp2rVO5J+TJAFfpPBLIukjmJ0 13 | FXFuC3ED6q8VOJrU0gVyb4z5K+taciX5OUbjchs+BMNkJyIQKopPWKcDrb60LhPt 14 | XapI19V91Cp7XPpGBFDkzA5CW4zt2/LP/JaT4NsRNlRiNDiPDGCbO5dWOK3z0luL 15 | oFvqTpa4fNfVoIZwQNORKbeiPK31jLvPGpKK5DR7wNhsX+kKwsOnIJpa3yxdUly6 16 | R9Wb7yQocDggL9V/KcCyQQNokszgnMyXS0XvOhAKq3A6mJVwrTWx6oUrpByAITGp 17 | rmB6gCZIALgBwJNjVSKRPFbnr9s6JfOPMVTqJouBWfmh0VMRxXudA/Z0EeBtsSw/ 18 | LIaRmXGapneLNGDRFLQsrJ2vjBDTn8Rq+G8T/HNZ92ZCdB6K4/jc0m+YnMtHmJVA 19 | BfvpAgMBAAGjggINMIICCTAdBgNVHQ4EFgQUdahxYEyIE/B42Yl3tW3Fid+8sXow 20 | gaMGA1UdIwSBmzCBmIAUFrUyG9TH8+DmjvO90rA67rI5GNGhfaR7MHkxEDAOBgNV 21 | BAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEiMCAG 22 | A1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYS 23 | c3VwcG9ydEBjYWNlcnQub3JnggEAMA8GA1UdEwEB/wQFMAMBAf8wXQYIKwYBBQUH 24 | AQEEUTBPMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5DQWNlcnQub3JnLzAoBggr 25 | BgEFBQcwAoYcaHR0cDovL3d3dy5DQWNlcnQub3JnL2NhLmNydDBKBgNVHSAEQzBB 26 | MD8GCCsGAQQBgZBKMDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuQ0FjZXJ0Lm9y 27 | Zy9pbmRleC5waHA/aWQ9MTAwNAYJYIZIAYb4QgEIBCcWJWh0dHA6Ly93d3cuQ0Fj 28 | ZXJ0Lm9yZy9pbmRleC5waHA/aWQ9MTAwUAYJYIZIAYb4QgENBEMWQVRvIGdldCB5 29 | b3VyIG93biBjZXJ0aWZpY2F0ZSBmb3IgRlJFRSwgZ28gdG8gaHR0cDovL3d3dy5D 30 | QWNlcnQub3JnMA0GCSqGSIb3DQEBCwUAA4ICAQApKIWuRKm5r6R5E/CooyuXYPNc 31 | 7uMvwfbiZqARrjY3OnYVBFPqQvX56sAV2KaC2eRhrnILKVyQQ+hBsuF32wITRHhH 32 | Va9Y/MyY9kW50SD42CEH/m2qc9SzxgfpCYXMO/K2viwcJdVxjDm1Luq+GIG6sJO4 33 | D+Pm1yaMMVpyA4RS5qb1MyJFCsgLDYq4Nm+QCaGrvdfVTi5xotSu+qdUK+s1jVq3 34 | VIgv7nSf7UgWyg1I0JTTrKSi9iTfkuO960NAkW4cGI5WtIIS86mTn9S8nK2cde5a 35 | lxuV53QtHA+wLJef+6kzOXrnAzqSjiL2jA3k2X4Ndhj3AfnvlpaiVXPAPHG0HRpW 36 | Q7fDCo1y/OIQCQtBzoyUoPkD/XFzS4pXM+WOdH4VAQDmzEoc53+VGS3FpQyLu7Xt 37 | hbNc09+4ufLKxw0BFKxwWMWMjTPUnWajGlCVI/xI4AZDEtnNp4Y5LzZyo4AQ5OHz 38 | 0ctbGsDkgJp8E3MGT9ujayQKurMcvEp4u+XjdTilSKeiHq921F73OIZWWonO1sOn 39 | ebJSoMbxhbQljPI/lrMQ2Y1sVzufb4Y6GIIiNsiwkTjbKqGTqoQ/9SdlrnPVyNXT 40 | d+pLncdBu8fA46A/5H2kjXPmEkvfoXNzczqA6NXLji/L6hOn1kGLrPo8idck9U60 41 | 4GGSt/M3mMS+lqO3ig== 42 | -----END CERTIFICATE----- 43 | -------------------------------------------------------------------------------- /test/cacerts.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matteocorti/check_ssl_cert/af6633dd450f14c1c725cff3ca12130d73a46e15/test/cacerts.jks -------------------------------------------------------------------------------- /test/cert_with_empty_subject.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDMzCCAhugAwIBAgIJANtVCnAolv4dMA0GCSqGSIb3DQEBDQUAMH4xCzAJBgNV 3 | BAYTAkRFMRswGQYDVQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxEjAQBgNVBAcMCVN0 4 | dXR0Z2FydDEcMBoGA1UECgwTLi4udW5kIHVlYmVyaGF1cHQhPzEPMA0GA1UECwwG 5 | dXVlIENBMQ8wDQYDVQQDDAZ1dWUgQ0EwHhcNMjAxMjIwMTYyNTM1WhcNMjExMjIw 6 | MTYyNTM1WjAAMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnvlsqMXz 7 | GDKdN0bochMAPx2/XTKxP4q8dsHqLnGGZ+VoNYecvJ/rXhvvWC9eeOknKZwaXe/H 8 | tOyITCc/L/4lx0krlCGcLH7AkVijlrgZeWbE/Ia/OUPlHYiVcXV0Pw8Hzy/+JdU/ 9 | BPkuCcxZhdwhB3k61HSdg8wAc/aJom9RveoI0dCweoeq7lHz5jv5Azjq5mK2rriB 10 | 4vMVTzzbLVAAQ451KrAkBNKaH+1Bvyn1S5SpMA+K4HnleBIGsc5ZnY03N2EAZq5h 11 | NczSBpdwZRkCxDXHpv6F4FIF7RJwCqgCpPRPsVuSr/KXFRnsSxhQCDiB4i3dEAwn 12 | iXJVHfHEmTe0UwIDAQABozIwMDAJBgNVHRMEAjAAMAsGA1UdDwQEAwIFoDAWBgNV 13 | HREEDzANggt3d3cudXVlLm9yZzANBgkqhkiG9w0BAQ0FAAOCAQEAdv5Z9KMWcItp 14 | 0ZsJlYEHmuHbw+lXvKzz11mY//D4HXSXthltc5dSW9wUJMWYiOJc8IoQnOOXo9Tx 15 | Ye8JvK6gOhOE8RELPr0e4jmIBCYq02bMh6v82EoN0gzI4ZgTfkLYZtVSGhUHYA8K 16 | 0gsPUz88VmVLrcz/EhOhbLuxmgUJWjE3z48zD/QO6TQRjVtwql5Qc2iBq9ZnCNgZ 17 | pf8r+/m561xMN5r3Jvp0+0xDM0gM5LigdObguUBzAhWExuHXHubcC0ovppSA5Qey 18 | uoalFu8pQXRTSZ9tatP7mYERciMtW+fK/MDbMNNVMcDgQoOtPna1zDFgqyEygLXy 19 | xZGfiGQBgw== 20 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /test/cert_with_subject_without_cn.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDdDCCAlygAwIBAgIJAL5rKAz6XKBNMA0GCSqGSIb3DQEBBQUAMHIxCzAJBgNV 3 | BAYTAkRFMRswGQYDVQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxEjAQBgNVBAcMCVN0 4 | dXR0Z2FydDEcMBoGA1UECgwTLi4udW5kIHVlYmVyaGF1cHQhPzEUMBIGA1UEAwwL 5 | dXVlIFJvb3QgQ0EwHhcNMjAxMjExMjAyNjI0WhcNMjExMjExMjAyNjI0WjBcMQsw 6 | CQYDVQQGEwJERTEbMBkGA1UECAwSQmFkZW4tV3VlcnR0ZW1iZXJnMRIwEAYDVQQH 7 | DAlTdHV0dGdhcnQxHDAaBgNVBAoMEy4uLnVuZCB1ZWJlcmhhdXB0IT8wggEiMA0G 8 | CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDX7icpGipAoscdhSvgepldiBizkZXq 9 | aM4KKdArbeG2SThiMuOqZesegKLI3oTcIfQA9Z1ZT0qk5XdN/uybTtkstGZduIr+ 10 | ZgvGZ605VVdOzbX9gQJ8yCj6/yUT+PLLhZXoHVqh0t2nkxr9Ed97iDeCbnnqPuKB 11 | tcdYrSIfxoPEonLiS0xVKb2qNBx2qfkseRkRBMYfh/1i9q29JoepkcUzqSH44Af/ 12 | oGlVeAhVMgOF0MS8Qa7LM+jx6qF4RQPiaCIj/UaNvX7idewiNf4QmEgbAaEjGtuk 13 | s92mHhze7IVleNjNTqVoLCfazLH2NLe51djfD8w60TlKRpD2Qt2aTOP9AgMBAAGj 14 | IzAhMB8GA1UdEQQYMBaCB3V1ZS5vcmeCC3d3dy51dWUub3JnMA0GCSqGSIb3DQEB 15 | BQUAA4IBAQBKdrw0i3npNbo80XDO0mHUuvsyBMTToaBL1F4SFtSauvtWaY9DF2RH 16 | gazu79y7n85czl4Nr7g4/HtZm2/oCxD6YeZEt+pHbTCIH7FVyfl5NrAza+Zs4TMs 17 | tujwB+JVsj9KD8MXEgBbohVYLMsA9vjVEA00I3hvro3rB/suvt4GnQyHHAsXrbuu 18 | eenCXULd0B4onD4ki2cUDXy3hArkO8LIwQ8iu55wYIgDlIX00Q2oPZRP+ZYCKdUl 19 | w5sjV1qPVtrDYzoeA5h/Ls5P0llZapnWGzJzmD6U6wk+zQAs+GgqlYrmEmNq97kL 20 | iRuLlubcbMknF/JN5mLUvgYqf7M71nEe 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /test/corti.li.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIGIjCCBQqgAwIBAgISBJ84k/CURk08+yag+pRoOuJUMA0GCSqGSIb3DQEBCwUA 3 | MDMxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQwwCgYDVQQD 4 | EwNSMTAwHhcNMjUwMjI2MDEyMjM0WhcNMjUwNTI3MDEyMjMzWjATMREwDwYDVQQD 5 | Ewhjb3J0aS5saTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMCC1/A 6 | UvZ9x8eMf9YSWmLNclZF64zYXLBC4Vxf4l/awZzLqF8cmCsVrpR+lAL0JSo5KFUw 7 | W073CtjCMIST2p1qi8/tON8dyqO7R60wCgvKNBxXRfNn2uvl7REARk84hFXS8Hba 8 | Tk8tMJ+CBUckX1rrrjqoJlNMMYJ4B8Yst3f8ZcJAWU6AeRXKhVFjCPQtVI6LMixa 9 | fLc2EUVLYSF7Vh6iUR+yHtLjyIGGsPbOxkPteJHkhHsARu30vl3uyxgUdWk2v0G/ 10 | VTnyJj81f6BfEp32VUTE1bbXwVVseRsu0hhnVu4CVc81h2EY2ytZRFpwVm4gtOf7 11 | QbB4ZGRGi0TJ4HcCAwEAAaOCA04wggNKMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUE 12 | FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU 13 | 6VXJt38Kesacc0kE1U1F2I/7+MUwHwYDVR0jBBgwFoAUu7zDR6XkvKnGw6RyDBCN 14 | ojXhyOgwVwYIKwYBBQUHAQEESzBJMCIGCCsGAQUFBzABhhZodHRwOi8vcjEwLm8u 15 | bGVuY3Iub3JnMCMGCCsGAQUFBzAChhdodHRwOi8vcjEwLmkubGVuY3Iub3JnLzCC 16 | AVQGA1UdEQSCAUswggFHghNibG9nLm1hdHRlb2NvcnRpLmNogghjb3J0aS5saYIR 17 | ZGVudGFsLWF0ZWxpZXIuY2iCE21hdHJpbW9uaW8uY29ydGkubGmCD21hdHRlby5j 18 | b3J0aS5saYIObWF0dGVvY29ydGkuY2iCE21pY2hlbGEtZS1tYXR0ZW8uY2iCDXBh 19 | c2kuY29ydGkubGmCDHJwbS5jb3J0aS5saYIPc2NvcmFkLmNvcnRpLmxpgg10ZXN0 20 | LmNvcnRpLmxpggx3d3cuY29ydGkubGmCFXd3dy5kZW50YWwtYXRlbGllci5jaIIS 21 | d3d3Lm1hdHRlb2NvcnRpLmNoghd3d3cubWljaGVsYS1lLW1hdHRlby5jaIIRd3d3 22 | LnBhc2kuY29ydGkubGmCE3d3dy5zY29yYWQuY29ydGkubGmCEXd3dy50ZXN0LmNv 23 | cnRpLmxpMBMGA1UdIAQMMAowCAYGZ4EMAQIBMIIBAwYKKwYBBAHWeQIEAgSB9ASB 24 | 8QDvAHYAzPsPaoVxCWX+lZtTzumyfCLphVwNl422qX5UwP5MDbAAAAGVQA7GkQAA 25 | BAMARzBFAiEAx/AzOmjHkl6Y90qMP106ApNkUGJtJsQJ2UTUvcwcD8ACIHKNRAud 26 | vNPTFQCGERQCyQaIDF8FihV41S9TiIAPRZlDAHUAouMK5EXvva2bfjjtR2d3U9eC 27 | W4SU1yteGyzEuVCkR+cAAAGVQA7GkAAABAMARjBEAiBwHkDqUJgKpo0FJIJuG7NI 28 | smaCTlvMKhKVvOesL4kZUAIgCN4IxlPyc4y+4v1QMi0XWBjUBzh1kb1qg5JieGMd 29 | riMwDQYJKoZIhvcNAQELBQADggEBABOA/4evRWiSWYC0TDx51Vg/b8THcvOk6kBb 30 | 35Q9u5IkJWoeW7Vcxqza0WG/JlC4XLw39cAw9sVA/aHkXQJt4P3HIes51dT1ef0I 31 | 5siFeBdOmDFueEbU9FAs9Pax1N3MNWj+QUuLJ0Cuno6eafS1arxoopUxwWFH0dLp 32 | cDsYjMRFrxPe0EeLOeLtg3p15DFsrqN+x1/ecbQ8NLej+5guRTz2loFxgeurQog0 33 | BFSveKTh93aAkuQaggNQPGR57EG3yHWatl87VxV5GUu1hOJHzXqWvI1vDCSJ/GB6 34 | c92ms6jII8rQ6s1BeWfwPc1hoUNWN5xEoz8LLYqqhKXK0YTVQAA= 35 | -----END CERTIFICATE----- 36 | -----BEGIN CERTIFICATE----- 37 | MIIFBTCCAu2gAwIBAgIQS6hSk/eaL6JzBkuoBI110DANBgkqhkiG9w0BAQsFADBP 38 | MQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFy 39 | Y2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMTAeFw0yNDAzMTMwMDAwMDBa 40 | Fw0yNzAzMTIyMzU5NTlaMDMxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBF 41 | bmNyeXB0MQwwCgYDVQQDEwNSMTAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK 42 | AoIBAQDPV+XmxFQS7bRH/sknWHZGUCiMHT6I3wWd1bUYKb3dtVq/+vbOo76vACFL 43 | YlpaPAEvxVgD9on/jhFD68G14BQHlo9vH9fnuoE5CXVlt8KvGFs3Jijno/QHK20a 44 | /6tYvJWuQP/py1fEtVt/eA0YYbwX51TGu0mRzW4Y0YCF7qZlNrx06rxQTOr8IfM4 45 | FpOUurDTazgGzRYSespSdcitdrLCnF2YRVxvYXvGLe48E1KGAdlX5jgc3421H5KR 46 | mudKHMxFqHJV8LDmowfs/acbZp4/SItxhHFYyTr6717yW0QrPHTnj7JHwQdqzZq3 47 | DZb3EoEmUVQK7GH29/Xi8orIlQ2NAgMBAAGjgfgwgfUwDgYDVR0PAQH/BAQDAgGG 48 | MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATASBgNVHRMBAf8ECDAGAQH/ 49 | AgEAMB0GA1UdDgQWBBS7vMNHpeS8qcbDpHIMEI2iNeHI6DAfBgNVHSMEGDAWgBR5 50 | tFnme7bl5AFzgAiIyBpY9umbbjAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAKG 51 | Fmh0dHA6Ly94MS5pLmxlbmNyLm9yZy8wEwYDVR0gBAwwCjAIBgZngQwBAgEwJwYD 52 | VR0fBCAwHjAcoBqgGIYWaHR0cDovL3gxLmMubGVuY3Iub3JnLzANBgkqhkiG9w0B 53 | AQsFAAOCAgEAkrHnQTfreZ2B5s3iJeE6IOmQRJWjgVzPw139vaBw1bGWKCIL0vIo 54 | zwzn1OZDjCQiHcFCktEJr59L9MhwTyAWsVrdAfYf+B9haxQnsHKNY67u4s5Lzzfd 55 | u6PUzeetUK29v+PsPmI2cJkxp+iN3epi4hKu9ZzUPSwMqtCceb7qPVxEbpYxY1p9 56 | 1n5PJKBLBX9eb9LU6l8zSxPWV7bK3lG4XaMJgnT9x3ies7msFtpKK5bDtotij/l0 57 | GaKeA97pb5uwD9KgWvaFXMIEt8jVTjLEvwRdvCn294GPDF08U8lAkIv7tghluaQh 58 | 1QnlE4SEN4LOECj8dsIGJXpGUk3aU3KkJz9icKy+aUgA+2cP21uh6NcDIS3XyfaZ 59 | QjmDQ993ChII8SXWupQZVBiIpcWO4RqZk3lr7Bz5MUCwzDIA359e57SSq5CCkY0N 60 | 4B6Vulk7LktfwrdGNVI5BsC9qqxSwSKgRJeZ9wygIaehbHFHFhcBaMDKpiZlBHyz 61 | rsnnlFXCb5s8HKn5LsUgGvB24L7sGNZP2CX7dhHov+YhD+jozLW2p9W4959Bz2Ei 62 | RmqDtmiXLnzqTpXbI+suyCsohKRg6Un0RC47+cpiVwHiXZAW+cn8eiNIjqbVgXLx 63 | KPpdzvvtTnOPlC7SQZSYmdunr3Bf9b77AiC/ZidstK36dRILKz7OA54= 64 | -----END CERTIFICATE----- 65 | -------------------------------------------------------------------------------- /test/der.cer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matteocorti/check_ssl_cert/af6633dd450f14c1c725cff3ca12130d73a46e15/test/der.cer -------------------------------------------------------------------------------- /test/derlink.cer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matteocorti/check_ssl_cert/af6633dd450f14c1c725cff3ca12130d73a46e15/test/derlink.cer -------------------------------------------------------------------------------- /test/fullchain.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFljCCA36gAwIBAgINAgO8U1lrNMcY9QFQZjANBgkqhkiG9w0BAQsFADBHMQsw 3 | CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU 4 | MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMjAwODEzMDAwMDQyWhcNMjcwOTMwMDAw 5 | MDQyWjBGMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp 6 | Y2VzIExMQzETMBEGA1UEAxMKR1RTIENBIDFDMzCCASIwDQYJKoZIhvcNAQEBBQAD 7 | ggEPADCCAQoCggEBAPWI3+dijB43+DdCkH9sh9D7ZYIl/ejLa6T/belaI+KZ9hzp 8 | kgOZE3wJCor6QtZeViSqejOEH9Hpabu5dOxXTGZok3c3VVP+ORBNtzS7XyV3NzsX 9 | lOo85Z3VvMO0Q+sup0fvsEQRY9i0QYXdQTBIkxu/t/bgRQIh4JZCF8/ZK2VWNAcm 10 | BA2o/X3KLu/qSHw3TT8An4Pf73WELnlXXPxXbhqW//yMmqaZviXZf5YsBvcRKgKA 11 | gOtjGDxQSYflispfGStZloEAoPtR28p3CwvJlk/vcEnHXG0g/Zm0tOLKLnf9LdwL 12 | tmsTDIwZKxeWmLnwi/agJ7u2441Rj72ux5uxiZ0CAwEAAaOCAYAwggF8MA4GA1Ud 13 | DwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0T 14 | AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUinR/r4XN7pXNPZzQ4kYU83E1HScwHwYD 15 | VR0jBBgwFoAU5K8rJnEaK0gnhS9SZizv8IkTcT4waAYIKwYBBQUHAQEEXDBaMCYG 16 | CCsGAQUFBzABhhpodHRwOi8vb2NzcC5wa2kuZ29vZy9ndHNyMTAwBggrBgEFBQcw 17 | AoYkaHR0cDovL3BraS5nb29nL3JlcG8vY2VydHMvZ3RzcjEuZGVyMDQGA1UdHwQt 18 | MCswKaAnoCWGI2h0dHA6Ly9jcmwucGtpLmdvb2cvZ3RzcjEvZ3RzcjEuY3JsMFcG 19 | A1UdIARQME4wOAYKKwYBBAHWeQIFAzAqMCgGCCsGAQUFBwIBFhxodHRwczovL3Br 20 | aS5nb29nL3JlcG9zaXRvcnkvMAgGBmeBDAECATAIBgZngQwBAgIwDQYJKoZIhvcN 21 | AQELBQADggIBAIl9rCBcDDy+mqhXlRu0rvqrpXJxtDaV/d9AEQNMwkYUuxQkq/BQ 22 | cSLbrcRuf8/xam/IgxvYzolfh2yHuKkMo5uhYpSTld9brmYZCwKWnvy15xBpPnrL 23 | RklfRuFBsdeYTWU0AIAaP0+fbH9JAIFTQaSSIYKCGvGjRFsqUBITTcFTNvNCCK9U 24 | +o53UxtkOCcXCb1YyRt8OS1b887U7ZfbFAO/CVMkH8IMBHmYJvJh8VNS/UKMG2Yr 25 | PxWhu//2m+OBmgEGcYk1KCTd4b3rGS3hSMs9WYNRtHTGnXzGsYZbr8w0xNPM1IER 26 | lQCh9BIiAfq0g3GvjLeMcySsN1PCAJA/Ef5c7TaUEDu9Ka7ixzpiO2xj2YC/WXGs 27 | Yye5TBeg2vZzFb8q3o/zpWwygTMD0IZRcZk0upONXbVRWPeyk+gB9lm+cZv9TSjO 28 | z23HFtz30dZGm6fKa+l3D/2gthsjgx0QGtkJAITgRNOidSOzNIb2ILCkXhAd4FJG 29 | AJ2xDx8hcFH1mt0G/FX0Kw4zd8NLQsLxdxP8c4CU6x+7Nz/OAipmsHMdMqUybDKw 30 | juDEI/9bfU1lcKwrmz3O2+BtjjKAvpafkmO8l7tdufThcV4q5O8DIrGKZTqPwJNl 31 | 1IXNDw9bg1kWRxYtnCQ6yICmJhSFm/Y3m6xv+cXDBlHz4n/FsRC6UfTd 32 | -----END CERTIFICATE----- 33 | -----BEGIN CERTIFICATE----- 34 | MIIFYjCCBEqgAwIBAgIQd70NbNs2+RrqIQ/E8FjTDTANBgkqhkiG9w0BAQsFADBX 35 | MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEQMA4GA1UE 36 | CxMHUm9vdCBDQTEbMBkGA1UEAxMSR2xvYmFsU2lnbiBSb290IENBMB4XDTIwMDYx 37 | OTAwMDA0MloXDTI4MDEyODAwMDA0MlowRzELMAkGA1UEBhMCVVMxIjAgBgNVBAoT 38 | GUdvb2dsZSBUcnVzdCBTZXJ2aWNlcyBMTEMxFDASBgNVBAMTC0dUUyBSb290IFIx 39 | MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAthECix7joXebO9y/lD63 40 | ladAPKH9gvl9MgaCcfb2jH/76Nu8ai6Xl6OMS/kr9rH5zoQdsfnFl97vufKj6bwS 41 | iV6nqlKr+CMny6SxnGPb15l+8Ape62im9MZaRw1NEDPjTrETo8gYbEvs/AmQ351k 42 | KSUjB6G00j0uYODP0gmHu81I8E3CwnqIiru6z1kZ1q+PsAewnjHxgsHA3y6mbWwZ 43 | DrXYfiYaRQM9sHmklCitD38m5agI/pboPGiUU+6DOogrFZYJsuB6jC511pzrp1Zk 44 | j5ZPaK49l8KEj8C8QMALXL32h7M1bKwYUH+E4EzNktMg6TO8UpmvMrUpsyUqtEj5 45 | cuHKZPfmghCN6J3Cioj6OGaK/GP5Afl4/Xtcd/p2h/rs37EOeZVXtL0m79YB0esW 46 | CruOC7XFxYpVq9Os6pFLKcwZpDIlTirxZUTQAs6qzkm06p98g7BAe+dDq6dso499 47 | iYH6TKX/1Y7DzkvgtdizjkXPdsDtQCv9Uw+wp9U7DbGKogPeMa3Md+pvez7W35Ei 48 | Eua++tgy/BBjFFFy3l3WFpO9KWgz7zpm7AeKJt8T11dleCfeXkkUAKIAf5qoIbap 49 | sZWwpbkNFhHax2xIPEDgfg1azVY80ZcFuctL7TlLnMQ/0lUTbiSw1nH69MG6zO0b 50 | 9f6BQdgAmD06yK56mDcYBZUCAwEAAaOCATgwggE0MA4GA1UdDwEB/wQEAwIBhjAP 51 | BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTkrysmcRorSCeFL1JmLO/wiRNxPjAf 52 | BgNVHSMEGDAWgBRge2YaRQ2XyolQL30EzTSo//z9SzBgBggrBgEFBQcBAQRUMFIw 53 | JQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnBraS5nb29nL2dzcjEwKQYIKwYBBQUH 54 | MAKGHWh0dHA6Ly9wa2kuZ29vZy9nc3IxL2dzcjEuY3J0MDIGA1UdHwQrMCkwJ6Al 55 | oCOGIWh0dHA6Ly9jcmwucGtpLmdvb2cvZ3NyMS9nc3IxLmNybDA7BgNVHSAENDAy 56 | MAgGBmeBDAECATAIBgZngQwBAgIwDQYLKwYBBAHWeQIFAwIwDQYLKwYBBAHWeQIF 57 | AwMwDQYJKoZIhvcNAQELBQADggEBADSkHrEoo9C0dhemMXoh6dFSPsjbdBZBiLg9 58 | NR3t5P+T4Vxfq7vqfM/b5A3Ri1fyJm9bvhdGaJQ3b2t6yMAYN/olUazsaL+yyEn9 59 | WprKASOshIArAoyZl+tJaox118fessmXn1hIVw41oeQa1v1vg4Fv74zPl6/AhSrw 60 | 9U5pCZEt4Wi4wStz6dTZ/CLANx8LZh1J7QJVj2fhMtfTJr9w4z30Z209fOU0iOMy 61 | +qduBmpvvYuR7hZL6Dupszfnw0Skfths18dG9ZKb59UhvmaSGZRVbNQpsg3BZlvi 62 | d0lIKO2d1xozclOzgjXPYovJJIultzkMu34qQb9Sz/yilrbCgj8= 63 | -----END CERTIFICATE----- 64 | 65 | -----BEGIN CERTIFICATE----- 66 | MIINxDCCDKygAwIBAgIQaczIXdXLFjQKAAAAAP9gXDANBgkqhkiG9w0BAQsFADBG 67 | MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM 68 | QzETMBEGA1UEAxMKR1RTIENBIDFDMzAeFw0yMTA5MTMwMTM4MzdaFw0yMTExMjAw 69 | MTM4MzZaMBcxFTATBgNVBAMMDCouZ29vZ2xlLmNvbTBZMBMGByqGSM49AgEGCCqG 70 | SM49AwEHA0IABF63ur9oci8z3kct0yU6SdxiU/D5SpKsSUTOWT5uRIUFtE4ZP6dI 71 | fhoZP3ZzJDGVHirnokMh3VxZaLZQMInFMDGjggumMIILojAOBgNVHQ8BAf8EBAMC 72 | B4AwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU 73 | 9X1jQB4WTJwnDM6S2qCd08XH8VowHwYDVR0jBBgwFoAUinR/r4XN7pXNPZzQ4kYU 74 | 83E1HScwagYIKwYBBQUHAQEEXjBcMCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcC5w 75 | a2kuZ29vZy9ndHMxYzMwMQYIKwYBBQUHMAKGJWh0dHA6Ly9wa2kuZ29vZy9yZXBv 76 | L2NlcnRzL2d0czFjMy5kZXIwgglWBgNVHREEgglNMIIJSYIMKi5nb29nbGUuY29t 77 | ghYqLmFwcGVuZ2luZS5nb29nbGUuY29tggkqLmJkbi5kZXaCEiouY2xvdWQuZ29v 78 | Z2xlLmNvbYIYKi5jcm93ZHNvdXJjZS5nb29nbGUuY29tghgqLmRhdGFjb21wdXRl 79 | Lmdvb2dsZS5jb22CCyouZ29vZ2xlLmNhggsqLmdvb2dsZS5jbIIOKi5nb29nbGUu 80 | Y28uaW6CDiouZ29vZ2xlLmNvLmpwgg4qLmdvb2dsZS5jby51a4IPKi5nb29nbGUu 81 | Y29tLmFygg8qLmdvb2dsZS5jb20uYXWCDyouZ29vZ2xlLmNvbS5icoIPKi5nb29n 82 | bGUuY29tLmNvgg8qLmdvb2dsZS5jb20ubXiCDyouZ29vZ2xlLmNvbS50coIPKi5n 83 | b29nbGUuY29tLnZuggsqLmdvb2dsZS5kZYILKi5nb29nbGUuZXOCCyouZ29vZ2xl 84 | LmZyggsqLmdvb2dsZS5odYILKi5nb29nbGUuaXSCCyouZ29vZ2xlLm5sggsqLmdv 85 | b2dsZS5wbIILKi5nb29nbGUucHSCEiouZ29vZ2xlYWRhcGlzLmNvbYIPKi5nb29n 86 | bGVhcGlzLmNughEqLmdvb2dsZXZpZGVvLmNvbYIMKi5nc3RhdGljLmNughAqLmdz 87 | dGF0aWMtY24uY29tghIqLmdzdGF0aWNjbmFwcHMuY26CD2dvb2dsZWNuYXBwcy5j 88 | boIRKi5nb29nbGVjbmFwcHMuY26CEWdvb2dsZWFwcHMtY24uY29tghMqLmdvb2ds 89 | ZWFwcHMtY24uY29tggxna2VjbmFwcHMuY26CDiouZ2tlY25hcHBzLmNughJnb29n 90 | bGVkb3dubG9hZHMuY26CFCouZ29vZ2xlZG93bmxvYWRzLmNughByZWNhcHRjaGEu 91 | bmV0LmNughIqLnJlY2FwdGNoYS5uZXQuY26CC3dpZGV2aW5lLmNugg0qLndpZGV2 92 | aW5lLmNughFhbXBwcm9qZWN0Lm9yZy5jboITKi5hbXBwcm9qZWN0Lm9yZy5jboIR 93 | YW1wcHJvamVjdC5uZXQuY26CEyouYW1wcHJvamVjdC5uZXQuY26CF2dvb2dsZS1h 94 | bmFseXRpY3MtY24uY29tghkqLmdvb2dsZS1hbmFseXRpY3MtY24uY29tghdnb29n 95 | bGVhZHNlcnZpY2VzLWNuLmNvbYIZKi5nb29nbGVhZHNlcnZpY2VzLWNuLmNvbYIR 96 | Z29vZ2xldmFkcy1jbi5jb22CEyouZ29vZ2xldmFkcy1jbi5jb22CEWdvb2dsZWFw 97 | aXMtY24uY29tghMqLmdvb2dsZWFwaXMtY24uY29tghVnb29nbGVvcHRpbWl6ZS1j 98 | bi5jb22CFyouZ29vZ2xlb3B0aW1pemUtY24uY29tghJkb3VibGVjbGljay1jbi5u 99 | ZXSCFCouZG91YmxlY2xpY2stY24ubmV0ghgqLmZscy5kb3VibGVjbGljay1jbi5u 100 | ZXSCFiouZy5kb3VibGVjbGljay1jbi5uZXSCDmRvdWJsZWNsaWNrLmNughAqLmRv 101 | dWJsZWNsaWNrLmNughQqLmZscy5kb3VibGVjbGljay5jboISKi5nLmRvdWJsZWNs 102 | aWNrLmNughFkYXJ0c2VhcmNoLWNuLm5ldIITKi5kYXJ0c2VhcmNoLWNuLm5ldIId 103 | Z29vZ2xldHJhdmVsYWRzZXJ2aWNlcy1jbi5jb22CHyouZ29vZ2xldHJhdmVsYWRz 104 | ZXJ2aWNlcy1jbi5jb22CGGdvb2dsZXRhZ3NlcnZpY2VzLWNuLmNvbYIaKi5nb29n 105 | bGV0YWdzZXJ2aWNlcy1jbi5jb22CF2dvb2dsZXRhZ21hbmFnZXItY24uY29tghkq 106 | Lmdvb2dsZXRhZ21hbmFnZXItY24uY29tghhnb29nbGVzeW5kaWNhdGlvbi1jbi5j 107 | b22CGiouZ29vZ2xlc3luZGljYXRpb24tY24uY29tgiQqLnNhZmVmcmFtZS5nb29n 108 | bGVzeW5kaWNhdGlvbi1jbi5jb22CFmFwcC1tZWFzdXJlbWVudC1jbi5jb22CGCou 109 | YXBwLW1lYXN1cmVtZW50LWNuLmNvbYILZ3Z0MS1jbi5jb22CDSouZ3Z0MS1jbi5j 110 | b22CC2d2dDItY24uY29tgg0qLmd2dDItY24uY29tggsybWRuLWNuLm5ldIINKi4y 111 | bWRuLWNuLm5ldIIUZ29vZ2xlZmxpZ2h0cy1jbi5uZXSCFiouZ29vZ2xlZmxpZ2h0 112 | cy1jbi5uZXSCDGFkbW9iLWNuLmNvbYIOKi5hZG1vYi1jbi5jb22CDSouZ3N0YXRp 113 | Yy5jb22CFCoubWV0cmljLmdzdGF0aWMuY29tggoqLmd2dDEuY29tghEqLmdjcGNk 114 | bi5ndnQxLmNvbYIKKi5ndnQyLmNvbYIOKi5nY3AuZ3Z0Mi5jb22CECoudXJsLmdv 115 | b2dsZS5jb22CFioueW91dHViZS1ub2Nvb2tpZS5jb22CCyoueXRpbWcuY29tggth 116 | bmRyb2lkLmNvbYINKi5hbmRyb2lkLmNvbYITKi5mbGFzaC5hbmRyb2lkLmNvbYIE 117 | Zy5jboIGKi5nLmNuggRnLmNvggYqLmcuY2+CBmdvby5nbIIKd3d3Lmdvby5nbIIU 118 | Z29vZ2xlLWFuYWx5dGljcy5jb22CFiouZ29vZ2xlLWFuYWx5dGljcy5jb22CCmdv 119 | b2dsZS5jb22CEmdvb2dsZWNvbW1lcmNlLmNvbYIUKi5nb29nbGVjb21tZXJjZS5j 120 | b22CCGdncGh0LmNuggoqLmdncGh0LmNuggp1cmNoaW4uY29tggwqLnVyY2hpbi5j 121 | b22CCHlvdXR1LmJlggt5b3V0dWJlLmNvbYINKi55b3V0dWJlLmNvbYIUeW91dHVi 122 | ZWVkdWNhdGlvbi5jb22CFioueW91dHViZWVkdWNhdGlvbi5jb22CD3lvdXR1YmVr 123 | aWRzLmNvbYIRKi55b3V0dWJla2lkcy5jb22CBXl0LmJlggcqLnl0LmJlghphbmRy 124 | b2lkLmNsaWVudHMuZ29vZ2xlLmNvbYIbZGV2ZWxvcGVyLmFuZHJvaWQuZ29vZ2xl 125 | LmNughxkZXZlbG9wZXJzLmFuZHJvaWQuZ29vZ2xlLmNughhzb3VyY2UuYW5kcm9p 126 | ZC5nb29nbGUuY24wIQYDVR0gBBowGDAIBgZngQwBAgEwDAYKKwYBBAHWeQIFAzA8 127 | BgNVHR8ENTAzMDGgL6AthitodHRwOi8vY3Jscy5wa2kuZ29vZy9ndHMxYzMvUU92 128 | SjBOMXNUMkEuY3JsMIIBBAYKKwYBBAHWeQIEAgSB9QSB8gDwAHcARJRlLrDuzq/E 129 | QAfYqP4owNrmgr7YyzG1P9MzlrW2gagAAAF73QViLQAABAMASDBGAiEArWffq368 130 | tzMiCHLl+A1BFjfaVIJORVMn4o43ejqiCToCIQC2XB2yUfqlhx8t70bRv9PsrATA 131 | VJeG4w1NoCvspRpCnAB1APZclC/RdzAiFFQYCDCUVo7jTRMZM7/fDC8gC8xO8WTj 132 | AAABe90FYRMAAAQDAEYwRAIgAZcPBI5OJaZQHgCD2qkmRAWyE3G60hQklI3psMyA 133 | yaICIAvd8zNVImiwu5RRhKkJ2c6sI9RABL43P9+cj0Qxddk8MA0GCSqGSIb3DQEB 134 | CwUAA4IBAQCTyIgyrPBdskJmSjsTLl6Dbe8Z9NuUCsqlL4t2L6MrZECzMxKag2H9 135 | pFdhSbQxjwdySgTwXWfVcAfuWxOw3qIrClr47G//aBN1m+Q35I73V3Ya16LKdoNm 136 | 3CLGe6qMArlBAg86q0Sr72OeZVKRuTya7l7wHRAMK1+nGCv5Acc+75q/HKj1OkVV 137 | njIG2whCZ+G5LmYZmKroEXIBUna3MGijHrlq58tFgQUSVQqVQzU2tseLIBvz284r 138 | iarLqQ7sR3xVM76Qgl+Be4A4z4fE7Dz1zRIbnetKn8YO5SO/B/H91EeIB4q+nmRO 139 | tYxFcW8qt9iyYP/rqp2q6lBmzkPLEpJH 140 | -----END CERTIFICATE----- 141 | -------------------------------------------------------------------------------- /test/incomplete_chain.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIINxDCCDKygAwIBAgIQaczIXdXLFjQKAAAAAP9gXDANBgkqhkiG9w0BAQsFADBG 3 | MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM 4 | QzETMBEGA1UEAxMKR1RTIENBIDFDMzAeFw0yMTA5MTMwMTM4MzdaFw0yMTExMjAw 5 | MTM4MzZaMBcxFTATBgNVBAMMDCouZ29vZ2xlLmNvbTBZMBMGByqGSM49AgEGCCqG 6 | SM49AwEHA0IABF63ur9oci8z3kct0yU6SdxiU/D5SpKsSUTOWT5uRIUFtE4ZP6dI 7 | fhoZP3ZzJDGVHirnokMh3VxZaLZQMInFMDGjggumMIILojAOBgNVHQ8BAf8EBAMC 8 | B4AwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU 9 | 9X1jQB4WTJwnDM6S2qCd08XH8VowHwYDVR0jBBgwFoAUinR/r4XN7pXNPZzQ4kYU 10 | 83E1HScwagYIKwYBBQUHAQEEXjBcMCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcC5w 11 | a2kuZ29vZy9ndHMxYzMwMQYIKwYBBQUHMAKGJWh0dHA6Ly9wa2kuZ29vZy9yZXBv 12 | L2NlcnRzL2d0czFjMy5kZXIwgglWBgNVHREEgglNMIIJSYIMKi5nb29nbGUuY29t 13 | ghYqLmFwcGVuZ2luZS5nb29nbGUuY29tggkqLmJkbi5kZXaCEiouY2xvdWQuZ29v 14 | Z2xlLmNvbYIYKi5jcm93ZHNvdXJjZS5nb29nbGUuY29tghgqLmRhdGFjb21wdXRl 15 | Lmdvb2dsZS5jb22CCyouZ29vZ2xlLmNhggsqLmdvb2dsZS5jbIIOKi5nb29nbGUu 16 | Y28uaW6CDiouZ29vZ2xlLmNvLmpwgg4qLmdvb2dsZS5jby51a4IPKi5nb29nbGUu 17 | Y29tLmFygg8qLmdvb2dsZS5jb20uYXWCDyouZ29vZ2xlLmNvbS5icoIPKi5nb29n 18 | bGUuY29tLmNvgg8qLmdvb2dsZS5jb20ubXiCDyouZ29vZ2xlLmNvbS50coIPKi5n 19 | b29nbGUuY29tLnZuggsqLmdvb2dsZS5kZYILKi5nb29nbGUuZXOCCyouZ29vZ2xl 20 | LmZyggsqLmdvb2dsZS5odYILKi5nb29nbGUuaXSCCyouZ29vZ2xlLm5sggsqLmdv 21 | b2dsZS5wbIILKi5nb29nbGUucHSCEiouZ29vZ2xlYWRhcGlzLmNvbYIPKi5nb29n 22 | bGVhcGlzLmNughEqLmdvb2dsZXZpZGVvLmNvbYIMKi5nc3RhdGljLmNughAqLmdz 23 | dGF0aWMtY24uY29tghIqLmdzdGF0aWNjbmFwcHMuY26CD2dvb2dsZWNuYXBwcy5j 24 | boIRKi5nb29nbGVjbmFwcHMuY26CEWdvb2dsZWFwcHMtY24uY29tghMqLmdvb2ds 25 | ZWFwcHMtY24uY29tggxna2VjbmFwcHMuY26CDiouZ2tlY25hcHBzLmNughJnb29n 26 | bGVkb3dubG9hZHMuY26CFCouZ29vZ2xlZG93bmxvYWRzLmNughByZWNhcHRjaGEu 27 | bmV0LmNughIqLnJlY2FwdGNoYS5uZXQuY26CC3dpZGV2aW5lLmNugg0qLndpZGV2 28 | aW5lLmNughFhbXBwcm9qZWN0Lm9yZy5jboITKi5hbXBwcm9qZWN0Lm9yZy5jboIR 29 | YW1wcHJvamVjdC5uZXQuY26CEyouYW1wcHJvamVjdC5uZXQuY26CF2dvb2dsZS1h 30 | bmFseXRpY3MtY24uY29tghkqLmdvb2dsZS1hbmFseXRpY3MtY24uY29tghdnb29n 31 | bGVhZHNlcnZpY2VzLWNuLmNvbYIZKi5nb29nbGVhZHNlcnZpY2VzLWNuLmNvbYIR 32 | Z29vZ2xldmFkcy1jbi5jb22CEyouZ29vZ2xldmFkcy1jbi5jb22CEWdvb2dsZWFw 33 | aXMtY24uY29tghMqLmdvb2dsZWFwaXMtY24uY29tghVnb29nbGVvcHRpbWl6ZS1j 34 | bi5jb22CFyouZ29vZ2xlb3B0aW1pemUtY24uY29tghJkb3VibGVjbGljay1jbi5u 35 | ZXSCFCouZG91YmxlY2xpY2stY24ubmV0ghgqLmZscy5kb3VibGVjbGljay1jbi5u 36 | ZXSCFiouZy5kb3VibGVjbGljay1jbi5uZXSCDmRvdWJsZWNsaWNrLmNughAqLmRv 37 | dWJsZWNsaWNrLmNughQqLmZscy5kb3VibGVjbGljay5jboISKi5nLmRvdWJsZWNs 38 | aWNrLmNughFkYXJ0c2VhcmNoLWNuLm5ldIITKi5kYXJ0c2VhcmNoLWNuLm5ldIId 39 | Z29vZ2xldHJhdmVsYWRzZXJ2aWNlcy1jbi5jb22CHyouZ29vZ2xldHJhdmVsYWRz 40 | ZXJ2aWNlcy1jbi5jb22CGGdvb2dsZXRhZ3NlcnZpY2VzLWNuLmNvbYIaKi5nb29n 41 | bGV0YWdzZXJ2aWNlcy1jbi5jb22CF2dvb2dsZXRhZ21hbmFnZXItY24uY29tghkq 42 | Lmdvb2dsZXRhZ21hbmFnZXItY24uY29tghhnb29nbGVzeW5kaWNhdGlvbi1jbi5j 43 | b22CGiouZ29vZ2xlc3luZGljYXRpb24tY24uY29tgiQqLnNhZmVmcmFtZS5nb29n 44 | bGVzeW5kaWNhdGlvbi1jbi5jb22CFmFwcC1tZWFzdXJlbWVudC1jbi5jb22CGCou 45 | YXBwLW1lYXN1cmVtZW50LWNuLmNvbYILZ3Z0MS1jbi5jb22CDSouZ3Z0MS1jbi5j 46 | b22CC2d2dDItY24uY29tgg0qLmd2dDItY24uY29tggsybWRuLWNuLm5ldIINKi4y 47 | bWRuLWNuLm5ldIIUZ29vZ2xlZmxpZ2h0cy1jbi5uZXSCFiouZ29vZ2xlZmxpZ2h0 48 | cy1jbi5uZXSCDGFkbW9iLWNuLmNvbYIOKi5hZG1vYi1jbi5jb22CDSouZ3N0YXRp 49 | Yy5jb22CFCoubWV0cmljLmdzdGF0aWMuY29tggoqLmd2dDEuY29tghEqLmdjcGNk 50 | bi5ndnQxLmNvbYIKKi5ndnQyLmNvbYIOKi5nY3AuZ3Z0Mi5jb22CECoudXJsLmdv 51 | b2dsZS5jb22CFioueW91dHViZS1ub2Nvb2tpZS5jb22CCyoueXRpbWcuY29tggth 52 | bmRyb2lkLmNvbYINKi5hbmRyb2lkLmNvbYITKi5mbGFzaC5hbmRyb2lkLmNvbYIE 53 | Zy5jboIGKi5nLmNuggRnLmNvggYqLmcuY2+CBmdvby5nbIIKd3d3Lmdvby5nbIIU 54 | Z29vZ2xlLWFuYWx5dGljcy5jb22CFiouZ29vZ2xlLWFuYWx5dGljcy5jb22CCmdv 55 | b2dsZS5jb22CEmdvb2dsZWNvbW1lcmNlLmNvbYIUKi5nb29nbGVjb21tZXJjZS5j 56 | b22CCGdncGh0LmNuggoqLmdncGh0LmNuggp1cmNoaW4uY29tggwqLnVyY2hpbi5j 57 | b22CCHlvdXR1LmJlggt5b3V0dWJlLmNvbYINKi55b3V0dWJlLmNvbYIUeW91dHVi 58 | ZWVkdWNhdGlvbi5jb22CFioueW91dHViZWVkdWNhdGlvbi5jb22CD3lvdXR1YmVr 59 | aWRzLmNvbYIRKi55b3V0dWJla2lkcy5jb22CBXl0LmJlggcqLnl0LmJlghphbmRy 60 | b2lkLmNsaWVudHMuZ29vZ2xlLmNvbYIbZGV2ZWxvcGVyLmFuZHJvaWQuZ29vZ2xl 61 | LmNughxkZXZlbG9wZXJzLmFuZHJvaWQuZ29vZ2xlLmNughhzb3VyY2UuYW5kcm9p 62 | ZC5nb29nbGUuY24wIQYDVR0gBBowGDAIBgZngQwBAgEwDAYKKwYBBAHWeQIFAzA8 63 | BgNVHR8ENTAzMDGgL6AthitodHRwOi8vY3Jscy5wa2kuZ29vZy9ndHMxYzMvUU92 64 | SjBOMXNUMkEuY3JsMIIBBAYKKwYBBAHWeQIEAgSB9QSB8gDwAHcARJRlLrDuzq/E 65 | QAfYqP4owNrmgr7YyzG1P9MzlrW2gagAAAF73QViLQAABAMASDBGAiEArWffq368 66 | tzMiCHLl+A1BFjfaVIJORVMn4o43ejqiCToCIQC2XB2yUfqlhx8t70bRv9PsrATA 67 | VJeG4w1NoCvspRpCnAB1APZclC/RdzAiFFQYCDCUVo7jTRMZM7/fDC8gC8xO8WTj 68 | AAABe90FYRMAAAQDAEYwRAIgAZcPBI5OJaZQHgCD2qkmRAWyE3G60hQklI3psMyA 69 | yaICIAvd8zNVImiwu5RRhKkJ2c6sI9RABL43P9+cj0Qxddk8MA0GCSqGSIb3DQEB 70 | CwUAA4IBAQCTyIgyrPBdskJmSjsTLl6Dbe8Z9NuUCsqlL4t2L6MrZECzMxKag2H9 71 | pFdhSbQxjwdySgTwXWfVcAfuWxOw3qIrClr47G//aBN1m+Q35I73V3Ya16LKdoNm 72 | 3CLGe6qMArlBAg86q0Sr72OeZVKRuTya7l7wHRAMK1+nGCv5Acc+75q/HKj1OkVV 73 | njIG2whCZ+G5LmYZmKroEXIBUna3MGijHrlq58tFgQUSVQqVQzU2tseLIBvz284r 74 | iarLqQ7sR3xVM76Qgl+Be4A4z4fE7Dz1zRIbnetKn8YO5SO/B/H91EeIB4q+nmRO 75 | tYxFcW8qt9iyYP/rqp2q6lBmzkPLEpJH 76 | -----END CERTIFICATE----- 77 | -------------------------------------------------------------------------------- /test/keystore.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matteocorti/check_ssl_cert/af6633dd450f14c1c725cff3ca12130d73a46e15/test/keystore.jks -------------------------------------------------------------------------------- /test/mosquitto.org.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEAzCCAuugAwIBAgIUBY1hlCGvdj4NhBXkZ/uLUZNILAwwDQYJKoZIhvcNAQEL 3 | BQAwgZAxCzAJBgNVBAYTAkdCMRcwFQYDVQQIDA5Vbml0ZWQgS2luZ2RvbTEOMAwG 4 | A1UEBwwFRGVyYnkxEjAQBgNVBAoMCU1vc3F1aXR0bzELMAkGA1UECwwCQ0ExFjAU 5 | BgNVBAMMDW1vc3F1aXR0by5vcmcxHzAdBgkqhkiG9w0BCQEWEHJvZ2VyQGF0Y2hv 6 | by5vcmcwHhcNMjAwNjA5MTEwNjM5WhcNMzAwNjA3MTEwNjM5WjCBkDELMAkGA1UE 7 | BhMCR0IxFzAVBgNVBAgMDlVuaXRlZCBLaW5nZG9tMQ4wDAYDVQQHDAVEZXJieTES 8 | MBAGA1UECgwJTW9zcXVpdHRvMQswCQYDVQQLDAJDQTEWMBQGA1UEAwwNbW9zcXVp 9 | dHRvLm9yZzEfMB0GCSqGSIb3DQEJARYQcm9nZXJAYXRjaG9vLm9yZzCCASIwDQYJ 10 | KoZIhvcNAQEBBQADggEPADCCAQoCggEBAME0HKmIzfTOwkKLT3THHe+ObdizamPg 11 | UZmD64Tf3zJdNeYGYn4CEXbyP6fy3tWc8S2boW6dzrH8SdFf9uo320GJA9B7U1FW 12 | Te3xda/Lm3JFfaHjkWw7jBwcauQZjpGINHapHRlpiCZsquAthOgxW9SgDgYlGzEA 13 | s06pkEFiMw+qDfLo/sxFKB6vQlFekMeCymjLCbNwPJyqyhFmPWwio/PDMruBTzPH 14 | 3cioBnrJWKXc3OjXdLGFJOfj7pP0j/dr2LH72eSvv3PQQFl90CZPFhrCUcRHSSxo 15 | E6yjGOdnz7f6PveLIB574kQORwt8ePn0yidrTC1ictikED3nHYhMUOUCAwEAAaNT 16 | MFEwHQYDVR0OBBYEFPVV6xBUFPiGKDyo5V3+Hbh4N9YSMB8GA1UdIwQYMBaAFPVV 17 | 6xBUFPiGKDyo5V3+Hbh4N9YSMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL 18 | BQADggEBAGa9kS21N70ThM6/Hj9D7mbVxKLBjVWe2TPsGfbl3rEDfZ+OKRZ2j6AC 19 | 6r7jb4TZO3dzF2p6dgbrlU71Y/4K0TdzIjRj3cQ3KSm41JvUQ0hZ/c04iGDg/xWf 20 | +pp58nfPAYwuerruPNWmlStWAXf0UTqRtg4hQDWBuUFDJTuWuuBvEXudz74eh/wK 21 | sMwfu1HFvjy5Z0iMDU8PUDepjVolOCue9ashlS4EB5IECdSR2TItnAIiIwimx839 22 | LdUdRudafMu5T5Xma182OC0/u/xRlEm+tvKGGmfFcN0piqVl8OrSPBgIlb+1IKJE 23 | m/XriWr/Cq4h/JfB7NTsezVslgkBaoU= 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /test/tinyproxy.conf: -------------------------------------------------------------------------------- 1 | Port 8888 2 | Listen 127.0.0.1 3 | Timeout 600 4 | Allow 127.0.0.1 5 | MaxClients 100 6 | StartServers 1 -------------------------------------------------------------------------------- /test/unit_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # $SHUNIT2 should be defined as an environment variable before running the tests 4 | # shellcheck disable=SC2154 5 | if [ -z "${SHUNIT2}" ]; then 6 | 7 | SHUNIT2=$(command -v shunit2) 8 | 9 | if [ -z "${SHUNIT2}" ]; then 10 | 11 | cat </dev/null)" 46 | 47 | if [ -z "${TEMPFILE}" ] || [ ! -w "${TEMPFILE}" ]; then 48 | fail 'temporary file creation failure.' 49 | fi 50 | 51 | # add the file to the list of temporary files 52 | TEMPORARY_FILES="${TEMPORARY_FILES} ${TEMPFILE}" 53 | 54 | } 55 | 56 | remove_temporary_test_files() { 57 | # shellcheck disable=SC2086 58 | if [ -n "${TEMPORARY_FILES}" ]; then 59 | rm -f ${TEMPORARY_FILES} 60 | fi 61 | } 62 | 63 | cleanup_temporary_test_files() { 64 | SIGNALS=$1 65 | remove_temporary_test_files 66 | # shellcheck disable=SC2086 67 | trap - ${SIGNALS} 68 | } 69 | 70 | createSelfSignedCertificate() { 71 | 72 | DAYS=$1 73 | 74 | if [ -z "${DAYS}" ]; then 75 | DAYS=30 # default 76 | fi 77 | 78 | create_temporary_test_file 79 | CONFIGURATION=${TEMPFILE} 80 | create_temporary_test_file 81 | KEY=${TEMPFILE} 82 | create_temporary_test_file 83 | CERTIFICATE=${TEMPFILE} 84 | 85 | cat <<'EOT' >"${CONFIGURATION}" 86 | [ req ] 87 | default_bits = 2048 88 | 89 | prompt = no 90 | distinguished_name=req_distinguished_name 91 | req_extensions = v3_req 92 | 93 | [ req_distinguished_name ] 94 | countryName=CH 95 | stateOrProvinceName=ZH 96 | localityName=Zurich 97 | organizationName=Matteo Corti 98 | organizationalUnitName=None 99 | commonName=localhost 100 | emailAddress=matteo@corti.li 101 | 102 | [ alternate_names ] 103 | DNS.1 = localhost 104 | 105 | [ v3_req ] 106 | keyUsage=digitalSignature 107 | subjectKeyIdentifier = hash 108 | subjectAltName = @alternate_names 109 | EOT 110 | 111 | ${OPENSSL} genrsa -out "${KEY}" 2048 >/dev/null 2>&1 112 | 113 | ${OPENSSL} req -new -x509 -key "${KEY}" -out "${CERTIFICATE}" -days "${DAYS}" -config "${CONFIGURATION}" 114 | 115 | echo "${CERTIFICATE}" 116 | 117 | } 118 | 119 | oneTimeSetUp() { 120 | # constants 121 | 122 | NAGIOS_OK=0 123 | NAGIOS_WARNING=1 124 | NAGIOS_CRITICAL=2 125 | NAGIOS_UNKNOWN=3 126 | 127 | COUNTER=1 128 | START_TIME=$(date +%s) 129 | 130 | if [ -z "${TMPDIR}" ]; then 131 | TMPDIR=/tmp 132 | fi 133 | 134 | # Cleanup before program termination 135 | # Using named signals to be POSIX compliant 136 | # shellcheck disable=SC2086 137 | trap_with_arg cleanup ${SIGNALS} 138 | 139 | # we trigger a test by Qualy's SSL so that when the last test is run the result will be cached 140 | echo 'Starting SSL Lab test (to cache the result)' 141 | curl --silent 'https://www.ssllabs.com/ssltest/analyze.html?d=ethz.ch&latest' >/dev/null 142 | 143 | # print the openssl version 144 | echo 'OpenSSL version' 145 | if [ -z "${OPENSSL}" ]; then 146 | OPENSSL=$(command -v openssl) # needed by openssl_version 147 | fi 148 | "${OPENSSL}" version 149 | 150 | KEYTOOL=$( command -v keytool) # Java? 151 | 152 | if [ -z "${GREP_BIN}" ]; then 153 | GREP_BIN=$(command -v grep) # needed by openssl_version 154 | fi 155 | if ! "${GREP_BIN}" -V >/dev/null 2>&1; then 156 | echo "Cannot determine grep version (Busybox?)" 157 | else 158 | "${GREP_BIN}" -V 159 | fi 160 | 161 | } 162 | 163 | seconds2String() { 164 | seconds=$1 165 | if [ "${seconds}" -gt 60 ]; then 166 | minutes=$((seconds / 60)) 167 | seconds=$((seconds % 60)) 168 | if [ "${minutes}" -gt 1 ]; then 169 | MINUTE_S="minutes" 170 | else 171 | MINUTE_S="minute" 172 | fi 173 | if [ "${seconds}" -eq 1 ]; then 174 | SECOND_S=" and ${seconds} second" 175 | elif [ "${seconds}" -eq 0 ]; then 176 | SECOND_S= 177 | else 178 | SECOND_S=" and ${seconds} seconds" 179 | fi 180 | string="${minutes} ${MINUTE_S}${SECOND_S}" 181 | else 182 | if [ "${seconds}" -eq 1 ]; then 183 | SECOND_S="second" 184 | else 185 | SECOND_S="seconds" 186 | fi 187 | string="${seconds} ${SECOND_S}" 188 | fi 189 | echo "${string}" 190 | 191 | } 192 | 193 | oneTimeTearDown() { 194 | # Cleanup before program termination 195 | # Using named signals to be POSIX compliant 196 | # shellcheck disable=SC2086 197 | cleanup_temporary_test_files ${SIGNALS} 198 | 199 | NOW=$(date +%s) 200 | ELAPSED=$((NOW - START_TIME)) 201 | # shellcheck disable=SC2154 202 | ELAPSED_STRING=$(seconds2String "${ELAPSED}") 203 | echo 204 | echo "Total time: ${ELAPSED_STRING}" 205 | } 206 | 207 | setUp() { 208 | echo 209 | 210 | # shellcheck disable=SC2154 211 | PERCENT=$(echo "scale=2; ${COUNTER} / ${__shunit_testsTotal} * 100" | bc | sed 's/[.].*//') 212 | 213 | NOW=$(date +%s) 214 | ELAPSED=$((NOW - START_TIME)) 215 | # shellcheck disable=SC2154 216 | REMAINING_S=$(echo "scale=2; ${__shunit_testsTotal} * ( ${ELAPSED} ) / ${COUNTER} - ${ELAPSED}" | bc | sed 's/[.].*//') 217 | if [ -z "${REMAINING_S}" ]; then 218 | REMAINING_S=0 219 | fi 220 | REMAINING=$(seconds2String "${REMAINING_S}") 221 | 222 | if [ -n "${http_proxy}" ]; then 223 | # print the test number 224 | # shellcheck disable=SC2154 225 | echo "Running test ${COUNTER} (proxy=${http_proxy}) of ${__shunit_testsTotal} (${PERCENT}%), ${REMAINING} remaining (${__shunit_testsFailed} failed)" 226 | else 227 | # print the test number 228 | # shellcheck disable=SC2154 229 | echo "Running test ${COUNTER} of ${__shunit_testsTotal} (${PERCENT}%), ${REMAINING} remaining (${__shunit_testsFailed} failed)" 230 | fi 231 | COUNTER=$((COUNTER + 1)) 232 | } 233 | 234 | ############################################################################## 235 | # Tests 236 | 237 | testHoursUntilNow() { 238 | # testing with perl 239 | if perl -e 'use Date::Parse;' >/dev/null 2>&1; then 240 | export DATETYPE='PERL' 241 | DATE_TMP="$(date)" 242 | hours_until "${DATE_TMP}" 243 | assertEquals "error computing the missing hours until now" 0 "${HOURS_UNTIL}" 244 | else 245 | echo "Date::Parse not installed: skipping Perl date computation tests" 246 | fi 247 | } 248 | 249 | testHoursUntil5Hours() { 250 | 251 | # testing with perl 252 | if perl -e 'use Date::Parse;' >/dev/null 2>&1; then 253 | export DATETYPE='PERL' 254 | DATE_TMP="$(perl -e '$x=localtime(time+(5*3600));print $x')" 255 | hours_until "${DATE_TMP}" 256 | assertEquals "error computing the missing hours until now" 5 "${HOURS_UNTIL}" 257 | else 258 | echo "Date::Parse not installed: skipping Perl date computation tests" 259 | fi 260 | } 261 | 262 | testHoursUntil42Hours() { 263 | # testing with perl 264 | if perl -e 'use Date::Parse;' >/dev/null 2>&1; then 265 | export DATETYPE='PERL' 266 | DATE_TMP="$(perl -e '$x=localtime(time+(42*3600));print $x')" 267 | hours_until "${DATE_TMP}" 268 | assertEquals "error computing the missing hours until now" 42 "${HOURS_UNTIL}" 269 | else 270 | echo "Date::Parse not installed: skipping Perl date computation tests" 271 | fi 272 | } 273 | 274 | testOpenSSLVersion1() { 275 | export OPENSSL_VERSION='OpenSSL 1.1.1j 16 Feb 2021' 276 | export REQUIRED_VERSION='1.2.0a' 277 | if [ -z "${OPENSSL}" ]; then 278 | OPENSSL=$(command -v openssl) # needed by openssl_version 279 | fi 280 | openssl_version "${REQUIRED_VERSION}" 281 | RET=$? 282 | assertEquals "error comparing required version ${REQUIRED_VERSION} to current version ${OPENSSL_VERSION}" 1 "${RET}" 283 | export OPENSSL_VERSION= 284 | } 285 | 286 | testOpenSSLVersion2() { 287 | export OPENSSL_VERSION='OpenSSL 1.1.1j 16 Feb 2021' 288 | export REQUIRED_VERSION='1.1.1j' 289 | if [ -z "${OPENSSL}" ]; then 290 | OPENSSL=$(command -v openssl) # needed by openssl_version 291 | fi 292 | openssl_version "${REQUIRED_VERSION}" 293 | RET=$? 294 | assertEquals "error comparing required version ${REQUIRED_VERSION} to current version ${OPENSSL_VERSION}" 0 "${RET}" 295 | export OPENSSL_VERSION= 296 | } 297 | 298 | testOpenSSLVersion3() { 299 | export OPENSSL_VERSION='OpenSSL 1.1.1j 16 Feb 2021' 300 | export REQUIRED_VERSION='1.0.0b' 301 | if [ -z "${OPENSSL}" ]; then 302 | OPENSSL=$(command -v openssl) # needed by openssl_version 303 | fi 304 | openssl_version "${REQUIRED_VERSION}" 305 | RET=$? 306 | assertEquals "error comparing required version ${REQUIRED_VERSION} to current version ${OPENSSL_VERSION}" 0 "${RET}" 307 | export OPENSSL_VERSION= 308 | } 309 | 310 | testOpenSSLVersion4() { 311 | export OPENSSL_VERSION='OpenSSL 1.0.2k-fips 26 Jan 2017' 312 | export REQUIRED_VERSION='1.0.0b' 313 | if [ -z "${OPENSSL}" ]; then 314 | OPENSSL=$(command -v openssl) # needed by openssl_version 315 | fi 316 | openssl_version "${REQUIRED_VERSION}" 317 | RET=$? 318 | assertEquals "error comparing required version ${REQUIRED_VERSION} to current version ${OPENSSL_VERSION}" 0 "${RET}" 319 | export OPENSSL_VERSION= 320 | } 321 | 322 | testOpenSSLVersion5() { 323 | export OPENSSL_VERSION='OpenSSL 1.1.1h-freebsd 22 Sep 2020' 324 | export REQUIRED_VERSION='1.0.0b' 325 | if [ -z "${OPENSSL}" ]; then 326 | OPENSSL=$(command -v openssl) # needed by openssl_version 327 | fi 328 | openssl_version "${REQUIRED_VERSION}" 329 | RET=$? 330 | assertEquals "error comparing required version ${REQUIRED_VERSION} to current version ${OPENSSL_VERSION}" 0 "${RET}" 331 | export OPENSSL_VERSION= 332 | } 333 | 334 | testDependencies() { 335 | check_required_prog openssl 336 | # $PROG is defined in the script 337 | # shellcheck disable=SC2154 338 | assertNotNull 'openssl not found' "${PROG}" 339 | } 340 | 341 | testUsage() { 342 | # shellcheck disable=SC2086 343 | ${SCRIPT} ${TEST_DEBUG} >/dev/null 2>&1 344 | EXIT_CODE=$? 345 | assertEquals "wrong exit code" "${NAGIOS_UNKNOWN}" "${EXIT_CODE}" 346 | } 347 | 348 | testMissingArgument() { 349 | # shellcheck disable=SC2086 350 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -H www.google.com --critical >/dev/null 2>&1 351 | EXIT_CODE=$? 352 | assertEquals "wrong exit code" "${NAGIOS_UNKNOWN}" "${EXIT_CODE}" 353 | } 354 | 355 | testMissingArgument2() { 356 | # shellcheck disable=SC2086 357 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -H www.google.com --critical --warning 10 >/dev/null 2>&1 358 | EXIT_CODE=$? 359 | assertEquals "wrong exit code" "${NAGIOS_UNKNOWN}" "${EXIT_CODE}" 360 | } 361 | 362 | testGroupedVariables() { 363 | # shellcheck disable=SC2086 364 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -H www.google.com -vvv --ignore-exp 365 | # >/dev/null 2>&1 366 | EXIT_CODE=$? 367 | assertEquals "wrong exit code" "${NAGIOS_OK}" "${EXIT_CODE}" 368 | } 369 | 370 | testGroupedVariablesError() { 371 | # shellcheck disable=SC2086 372 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -H www.google.com -vvxv >/dev/null 2>&1 373 | EXIT_CODE=$? 374 | assertEquals "wrong exit code" "${NAGIOS_UNKNOWN}" "${EXIT_CODE}" 375 | } 376 | 377 | testTimeOut() { 378 | # shellcheck disable=SC2086 379 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -H gmail.com --protocol imap --port 993 --timeout 1 --ignore-exp 380 | EXIT_CODE=$? 381 | assertEquals "wrong exit code" "${NAGIOS_CRITICAL}" "${EXIT_CODE}" 382 | } 383 | 384 | testRequiredProgramFile() { 385 | # shellcheck disable=SC2086 386 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -H www.google.com --file-bin /doesnotexist --ignore-exp 387 | EXIT_CODE=$? 388 | assertEquals "wrong exit code" "${NAGIOS_UNKNOWN}" "${EXIT_CODE}" 389 | } 390 | 391 | testRequiredProgramPermissions() { 392 | # shellcheck disable=SC2086 393 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -H www.google.com --file-bin /etc/hosts --ignore-exp 394 | EXIT_CODE=$? 395 | assertEquals "wrong exit code" "${NAGIOS_UNKNOWN}" "${EXIT_CODE}" 396 | } 397 | 398 | testNotLongerValidThan() { 399 | # shellcheck disable=SC2086 400 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -H www.github.com --not-valid-longer-than 2 401 | EXIT_CODE=$? 402 | assertEquals "wrong exit code" "${NAGIOS_CRITICAL}" "${EXIT_CODE}" 403 | } 404 | 405 | testDERCert() { 406 | # shellcheck disable=SC2086 407 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -f ./der.cer --ignore-sct --ignore-exp --allow-empty-san -s 408 | EXIT_CODE=$? 409 | assertEquals "wrong exit code" "${NAGIOS_OK}" "${EXIT_CODE}" 410 | } 411 | 412 | testDERCertURI() { 413 | # shellcheck disable=SC2086 414 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -f "file://${PWD}/der.cer" --ignore-sct --ignore-exp --allow-empty-san -s 415 | EXIT_CODE=$? 416 | assertEquals "wrong exit code" "${NAGIOS_OK}" "${EXIT_CODE}" 417 | } 418 | 419 | testDERCertSymbolicLink() { 420 | # shellcheck disable=SC2086 421 | ${SCRIPT} ${TEST_DEBUG} --rootcert-file cabundle.crt -f ./derlink.cer --ignore-sct --ignore-exp --allow-empty-san -s 422 | EXIT_CODE=$? 423 | assertEquals "wrong exit code" "${NAGIOS_OK}" "${EXIT_CODE}" 424 | } 425 | 426 | testCertificateWithEmptySAN() { 427 | CERT=$(createSelfSignedCertificate 30) 428 | 429 | # shellcheck disable=SC2086 430 | ${SCRIPT} ${TEST_DEBUG} -f "${CERT}" --selfsigned --allow-empty-san --ignore-sig-alg --ignore-exp -m localhost 431 | EXIT_CODE=$? 432 | 433 | assertEquals "wrong exit code" "${NAGIOS_OK}" "${EXIT_CODE}" 434 | } 435 | 436 | testCertificateWithEmptySANFail() { 437 | # Test with wrong CN's 438 | CERT=$(createSelfSignedCertificate 30) 439 | 440 | # shellcheck disable=SC2086 441 | ${SCRIPT} ${TEST_DEBUG} -f "${CERT}" --selfsigned --allow-empty-san --ignore-sig-alg --ignore-exp -m wrong.com 442 | EXIT_CODE=$? 443 | 444 | assertEquals "wrong exit code" "${NAGIOS_CRITICAL}" "${EXIT_CODE}" 445 | } 446 | 447 | testFloatingPointThresholds() { 448 | 449 | # shellcheck disable=SC2086 450 | ${SCRIPT} ${TEST_DEBUG} -H google.com --warning 2.5 --critical 1.5 451 | EXIT_CODE=$? 452 | assertEquals "wrong exit code" "${NAGIOS_OK}" "${EXIT_CODE}" 453 | 454 | } 455 | 456 | testFloatingPointThresholdsExpired() { 457 | 458 | # shellcheck disable=SC2086 459 | ${SCRIPT} ${TEST_DEBUG} -H expired.badssl.com --warning 2.5 --critical 1.5 460 | EXIT_CODE=$? 461 | assertEquals "wrong exit code" "${NAGIOS_CRITICAL}" "${EXIT_CODE}" 462 | 463 | } 464 | 465 | testFloatingPointThresholdsWrongUsage() { 466 | 467 | # shellcheck disable=SC2086 468 | ${SCRIPT} ${TEST_DEBUG} -H github.com --warning 1.5 --critical 2.5 469 | EXIT_CODE=$? 470 | assertEquals "expecting error message about --warning is less or equal --critical, but got wrong exit code, " "${NAGIOS_UNKNOWN}" "${EXIT_CODE}" 471 | 472 | } 473 | 474 | testCertExpiringInLessThanOneDay() { 475 | 476 | CERT=$(createSelfSignedCertificate 1) 477 | 478 | # shellcheck disable=SC2086 479 | ${SCRIPT} ${TEST_DEBUG} -f "${CERT}" --warning 1.5 --critical 0.5 --selfsigned --allow-empty-san --ignore-sig-alg 480 | EXIT_CODE=$? 481 | 482 | assertEquals "wrong exit code" "${NAGIOS_WARNING}" "${EXIT_CODE}" 483 | 484 | } 485 | 486 | testMaxDateOn32BitSystems() { 487 | 488 | # generate a cert expiring after 2038-01-19 489 | CERT=$(createSelfSignedCertificate 7000) 490 | 491 | # shellcheck disable=SC2086 492 | ${SCRIPT} ${TEST_DEBUG} -f "${CERT}" --warning 2 --critical 1 --selfsigned --allow-empty-san --ignore-sig-alg --ignore-maximum-validity 493 | EXIT_CODE=$? 494 | 495 | assertEquals "wrong exit code" "${NAGIOS_OK}" "${EXIT_CODE}" 496 | 497 | # shellcheck disable=SC2086 498 | ${SCRIPT} ${TEST_DEBUG} -f "${CERT}" --warning 2 --critical 1 --selfsigned --allow-empty-san --ignore-sig-alg --ignore-maximum-validity 2>&1 | grep -q 'invalid date' 499 | EXIT_CODE=$? 500 | 501 | assertEquals "Invalid date" 1 "${EXIT_CODE}" 502 | 503 | } 504 | 505 | testMaximumValidityFailed() { 506 | # generate a cert expiring in 400 days 507 | CERT=$(createSelfSignedCertificate 400) 508 | # shellcheck disable=SC2086 509 | ${SCRIPT} ${TEST_DEBUG} -f "${CERT}" --selfsigned --allow-empty-san --ignore-sig-alg 510 | EXIT_CODE=$? 511 | assertEquals "wrong exit code" "${NAGIOS_CRITICAL}" "${EXIT_CODE}" 512 | } 513 | 514 | testMaximumValidityShort() { 515 | # generate a cert expiring in 400 days 516 | CERT=$(createSelfSignedCertificate 400) 517 | # shellcheck disable=SC2086 518 | ${SCRIPT} ${TEST_DEBUG} -f "${CERT}" --selfsigned --allow-empty-san --ignore-sig-alg --maximum-validity 20 519 | EXIT_CODE=$? 520 | assertEquals "wrong exit code" "${NAGIOS_CRITICAL}" "${EXIT_CODE}" 521 | } 522 | 523 | testMaximumValidityLong() { 524 | # generate a cert expiring in 400 days 525 | CERT=$(createSelfSignedCertificate 400) 526 | # shellcheck disable=SC2086 527 | ${SCRIPT} ${TEST_DEBUG} -f "${CERT}" --selfsigned --allow-empty-san --ignore-sig-alg --maximum-validity 500 528 | EXIT_CODE=$? 529 | assertEquals "wrong exit code" "${NAGIOS_OK}" "${EXIT_CODE}" 530 | } 531 | 532 | testMaximumValidityIgnored() { 533 | # generate a cert expiring in 400 days 534 | CERT=$(createSelfSignedCertificate 400) 535 | # shellcheck disable=SC2086 536 | ${SCRIPT} ${TEST_DEBUG} -f "${CERT}" --selfsigned --allow-empty-san --ignore-sig-alg --ignore-maximum-validity 537 | EXIT_CODE=$? 538 | assertEquals "wrong exit code" "${NAGIOS_OK}" "${EXIT_CODE}" 539 | } 540 | 541 | testChainOK() { 542 | # shellcheck disable=SC2086 543 | ${SCRIPT} ${TEST_DEBUG} -f ./fullchain.pem --allow-empty-san --ignore-sct --ignore-exp --ignore-maximum-validity 544 | EXIT_CODE=$? 545 | assertEquals "wrong exit code" "${NAGIOS_OK}" "${EXIT_CODE}" 546 | } 547 | 548 | testChainFail() { 549 | # shellcheck disable=SC2086 550 | ${SCRIPT} ${TEST_DEBUG} -f ./incomplete_chain.pem --allow-empty-san --ignore-sct --ignore-exp 551 | EXIT_CODE=$? 552 | assertEquals "wrong exit code" "${NAGIOS_CRITICAL}" "${EXIT_CODE}" 553 | } 554 | 555 | testChainFailIgnored() { 556 | # shellcheck disable=SC2086 557 | ${SCRIPT} ${TEST_DEBUG} -f ./incomplete_chain.pem --ignore-incomplete-chain --allow-empty-san --ignore-sct --ignore-exp 558 | EXIT_CODE=$? 559 | assertEquals "wrong exit code" "${NAGIOS_OK}" "${EXIT_CODE}" 560 | } 561 | 562 | testJavaKeyStore1() { 563 | if [ -n "${KEYTOOL}" ] ; then 564 | # shellcheck disable=SC2086 565 | ${SCRIPT} ${TEST_DEBUG} --file ./keystore.jks --password changeit --jks-alias google-com --ignore-incomplete-chain --ignore-exp 566 | EXIT_CODE=$? 567 | assertEquals "wrong exit code" "${NAGIOS_OK}" "${EXIT_CODE}" 568 | else 569 | echo "Java not installed: skipping key store tests" 570 | fi 571 | } 572 | 573 | testJavaKeyStore2() { 574 | if [ -n "${KEYTOOL}" ] ; then 575 | # shellcheck disable=SC2086 576 | ${SCRIPT} ${TEST_DEBUG} --file ./cacerts.jks --password changeit --jks-alias "verisignuniversalrootca [jdk]" --allow-empty-san --ignore-maximum-validity --selfsigned 577 | EXIT_CODE=$? 578 | assertEquals "wrong exit code" "${NAGIOS_OK}" "${EXIT_CODE}" 579 | else 580 | echo "Java not installed: skipping key store tests" 581 | fi 582 | } 583 | 584 | testDirectoryAsAFile() { 585 | # shellcheck disable=SC2086 586 | ${SCRIPT} ${TEST_DEBUG} --file somedir 587 | EXIT_CODE=$? 588 | assertEquals "wrong exit code" "${NAGIOS_CRITICAL}" "${EXIT_CODE}" 589 | } 590 | 591 | # the script will exit without executing main 592 | export SOURCE_ONLY='test' 593 | 594 | # source the script. 595 | # Do not follow 596 | # shellcheck disable=SC1090 597 | . "${SCRIPT}" 598 | 599 | unset SOURCE_ONLY 600 | 601 | # run shUnit: it will execute all the tests in this file 602 | # (e.g., functions beginning with 'test' 603 | # 604 | # We clone to output to pass it to grep as shunit does always return 0 605 | # We parse the output to check if a test failed 606 | # 607 | 608 | # Do not follow 609 | # shellcheck disable=SC1090 610 | . "${SHUNIT2}" 611 | -------------------------------------------------------------------------------- /test/wrong_chain.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFADCCA+igAwIBAgIBBzANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx 3 | EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT 4 | HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs 5 | ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTExMDUwMzA3MDAw 6 | MFoXDTMxMDUwMzA3MDAwMFowgcYxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 7 | b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj 8 | aG5vbG9naWVzLCBJbmMuMTMwMQYDVQQLEypodHRwOi8vY2VydHMuc3RhcmZpZWxk 9 | dGVjaC5jb20vcmVwb3NpdG9yeS8xNDAyBgNVBAMTK1N0YXJmaWVsZCBTZWN1cmUg 10 | Q2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IB 11 | DwAwggEKAoIBAQDlkGZL7PlGcakgg77pbL9KyUhpgXVObST2yxcT+LBxWYR6ayuF 12 | pDS1FuXLzOlBcCykLtb6Mn3hqN6UEKwxwcDYav9ZJ6t21vwLdGu4p64/xFT0tDFE 13 | 3ZNWjKRMXpuJyySDm+JXfbfYEh/JhW300YDxUJuHrtQLEAX7J7oobRfpDtZNuTlV 14 | Bv8KJAV+L8YdcmzUiymMV33a2etmGtNPp99/UsQwxaXJDgLFU793OGgGJMNmyDd+ 15 | MB5FcSM1/5DYKp2N57CSTTx/KgqT3M0WRmX3YISLdkuRJ3MUkuDq7o8W6o0OPnYX 16 | v32JgIBEQ+ct4EMJddo26K3biTr1XRKOIwSDAgMBAAGjggEsMIIBKDAPBgNVHRMB 17 | Af8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUJUWBaFAmOD07LSy+ 18 | zWrZtj2zZmMwHwYDVR0jBBgwFoAUfAwyH6fZMH/EfWijYqihzqsHWycwOgYIKwYB 19 | BQUHAQEELjAsMCoGCCsGAQUFBzABhh5odHRwOi8vb2NzcC5zdGFyZmllbGR0ZWNo 20 | LmNvbS8wOwYDVR0fBDQwMjAwoC6gLIYqaHR0cDovL2NybC5zdGFyZmllbGR0ZWNo 21 | LmNvbS9zZnJvb3QtZzIuY3JsMEwGA1UdIARFMEMwQQYEVR0gADA5MDcGCCsGAQUF 22 | BwIBFitodHRwczovL2NlcnRzLnN0YXJmaWVsZHRlY2guY29tL3JlcG9zaXRvcnkv 23 | MA0GCSqGSIb3DQEBCwUAA4IBAQBWZcr+8z8KqJOLGMfeQ2kTNCC+Tl94qGuc22pN 24 | QdvBE+zcMQAiXvcAngzgNGU0+bE6TkjIEoGIXFs+CFN69xpk37hQYcxTUUApS8L0 25 | rjpf5MqtJsxOYUPl/VemN3DOQyuwlMOS6eFfqhBJt2nk4NAfZKQrzR9voPiEJBjO 26 | eT2pkb9UGBOJmVQRDVXFJgt5T1ocbvlj2xSApAer+rKluYjdkf5lO6Sjeb6JTeHQ 27 | sPTIFwwKlhR8Cbds4cLYVdQYoKpBaXAko7nv6VrcPuuUSvC33l8Odvr7+2kDRUBQ 28 | 7nIMpBKGgc0T0U7EPMpODdIm8QC3tKai4W56gf0wrHofx1l7 29 | -----END CERTIFICATE----- 30 | 31 | -----BEGIN CERTIFICATE----- 32 | MIINxDCCDKygAwIBAgIQaczIXdXLFjQKAAAAAP9gXDANBgkqhkiG9w0BAQsFADBG 33 | MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM 34 | QzETMBEGA1UEAxMKR1RTIENBIDFDMzAeFw0yMTA5MTMwMTM4MzdaFw0yMTExMjAw 35 | MTM4MzZaMBcxFTATBgNVBAMMDCouZ29vZ2xlLmNvbTBZMBMGByqGSM49AgEGCCqG 36 | SM49AwEHA0IABF63ur9oci8z3kct0yU6SdxiU/D5SpKsSUTOWT5uRIUFtE4ZP6dI 37 | fhoZP3ZzJDGVHirnokMh3VxZaLZQMInFMDGjggumMIILojAOBgNVHQ8BAf8EBAMC 38 | B4AwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU 39 | 9X1jQB4WTJwnDM6S2qCd08XH8VowHwYDVR0jBBgwFoAUinR/r4XN7pXNPZzQ4kYU 40 | 83E1HScwagYIKwYBBQUHAQEEXjBcMCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcC5w 41 | a2kuZ29vZy9ndHMxYzMwMQYIKwYBBQUHMAKGJWh0dHA6Ly9wa2kuZ29vZy9yZXBv 42 | L2NlcnRzL2d0czFjMy5kZXIwgglWBgNVHREEgglNMIIJSYIMKi5nb29nbGUuY29t 43 | ghYqLmFwcGVuZ2luZS5nb29nbGUuY29tggkqLmJkbi5kZXaCEiouY2xvdWQuZ29v 44 | Z2xlLmNvbYIYKi5jcm93ZHNvdXJjZS5nb29nbGUuY29tghgqLmRhdGFjb21wdXRl 45 | Lmdvb2dsZS5jb22CCyouZ29vZ2xlLmNhggsqLmdvb2dsZS5jbIIOKi5nb29nbGUu 46 | Y28uaW6CDiouZ29vZ2xlLmNvLmpwgg4qLmdvb2dsZS5jby51a4IPKi5nb29nbGUu 47 | Y29tLmFygg8qLmdvb2dsZS5jb20uYXWCDyouZ29vZ2xlLmNvbS5icoIPKi5nb29n 48 | bGUuY29tLmNvgg8qLmdvb2dsZS5jb20ubXiCDyouZ29vZ2xlLmNvbS50coIPKi5n 49 | b29nbGUuY29tLnZuggsqLmdvb2dsZS5kZYILKi5nb29nbGUuZXOCCyouZ29vZ2xl 50 | LmZyggsqLmdvb2dsZS5odYILKi5nb29nbGUuaXSCCyouZ29vZ2xlLm5sggsqLmdv 51 | b2dsZS5wbIILKi5nb29nbGUucHSCEiouZ29vZ2xlYWRhcGlzLmNvbYIPKi5nb29n 52 | bGVhcGlzLmNughEqLmdvb2dsZXZpZGVvLmNvbYIMKi5nc3RhdGljLmNughAqLmdz 53 | dGF0aWMtY24uY29tghIqLmdzdGF0aWNjbmFwcHMuY26CD2dvb2dsZWNuYXBwcy5j 54 | boIRKi5nb29nbGVjbmFwcHMuY26CEWdvb2dsZWFwcHMtY24uY29tghMqLmdvb2ds 55 | ZWFwcHMtY24uY29tggxna2VjbmFwcHMuY26CDiouZ2tlY25hcHBzLmNughJnb29n 56 | bGVkb3dubG9hZHMuY26CFCouZ29vZ2xlZG93bmxvYWRzLmNughByZWNhcHRjaGEu 57 | bmV0LmNughIqLnJlY2FwdGNoYS5uZXQuY26CC3dpZGV2aW5lLmNugg0qLndpZGV2 58 | aW5lLmNughFhbXBwcm9qZWN0Lm9yZy5jboITKi5hbXBwcm9qZWN0Lm9yZy5jboIR 59 | YW1wcHJvamVjdC5uZXQuY26CEyouYW1wcHJvamVjdC5uZXQuY26CF2dvb2dsZS1h 60 | bmFseXRpY3MtY24uY29tghkqLmdvb2dsZS1hbmFseXRpY3MtY24uY29tghdnb29n 61 | bGVhZHNlcnZpY2VzLWNuLmNvbYIZKi5nb29nbGVhZHNlcnZpY2VzLWNuLmNvbYIR 62 | Z29vZ2xldmFkcy1jbi5jb22CEyouZ29vZ2xldmFkcy1jbi5jb22CEWdvb2dsZWFw 63 | aXMtY24uY29tghMqLmdvb2dsZWFwaXMtY24uY29tghVnb29nbGVvcHRpbWl6ZS1j 64 | bi5jb22CFyouZ29vZ2xlb3B0aW1pemUtY24uY29tghJkb3VibGVjbGljay1jbi5u 65 | ZXSCFCouZG91YmxlY2xpY2stY24ubmV0ghgqLmZscy5kb3VibGVjbGljay1jbi5u 66 | ZXSCFiouZy5kb3VibGVjbGljay1jbi5uZXSCDmRvdWJsZWNsaWNrLmNughAqLmRv 67 | dWJsZWNsaWNrLmNughQqLmZscy5kb3VibGVjbGljay5jboISKi5nLmRvdWJsZWNs 68 | aWNrLmNughFkYXJ0c2VhcmNoLWNuLm5ldIITKi5kYXJ0c2VhcmNoLWNuLm5ldIId 69 | Z29vZ2xldHJhdmVsYWRzZXJ2aWNlcy1jbi5jb22CHyouZ29vZ2xldHJhdmVsYWRz 70 | ZXJ2aWNlcy1jbi5jb22CGGdvb2dsZXRhZ3NlcnZpY2VzLWNuLmNvbYIaKi5nb29n 71 | bGV0YWdzZXJ2aWNlcy1jbi5jb22CF2dvb2dsZXRhZ21hbmFnZXItY24uY29tghkq 72 | Lmdvb2dsZXRhZ21hbmFnZXItY24uY29tghhnb29nbGVzeW5kaWNhdGlvbi1jbi5j 73 | b22CGiouZ29vZ2xlc3luZGljYXRpb24tY24uY29tgiQqLnNhZmVmcmFtZS5nb29n 74 | bGVzeW5kaWNhdGlvbi1jbi5jb22CFmFwcC1tZWFzdXJlbWVudC1jbi5jb22CGCou 75 | YXBwLW1lYXN1cmVtZW50LWNuLmNvbYILZ3Z0MS1jbi5jb22CDSouZ3Z0MS1jbi5j 76 | b22CC2d2dDItY24uY29tgg0qLmd2dDItY24uY29tggsybWRuLWNuLm5ldIINKi4y 77 | bWRuLWNuLm5ldIIUZ29vZ2xlZmxpZ2h0cy1jbi5uZXSCFiouZ29vZ2xlZmxpZ2h0 78 | cy1jbi5uZXSCDGFkbW9iLWNuLmNvbYIOKi5hZG1vYi1jbi5jb22CDSouZ3N0YXRp 79 | Yy5jb22CFCoubWV0cmljLmdzdGF0aWMuY29tggoqLmd2dDEuY29tghEqLmdjcGNk 80 | bi5ndnQxLmNvbYIKKi5ndnQyLmNvbYIOKi5nY3AuZ3Z0Mi5jb22CECoudXJsLmdv 81 | b2dsZS5jb22CFioueW91dHViZS1ub2Nvb2tpZS5jb22CCyoueXRpbWcuY29tggth 82 | bmRyb2lkLmNvbYINKi5hbmRyb2lkLmNvbYITKi5mbGFzaC5hbmRyb2lkLmNvbYIE 83 | Zy5jboIGKi5nLmNuggRnLmNvggYqLmcuY2+CBmdvby5nbIIKd3d3Lmdvby5nbIIU 84 | Z29vZ2xlLWFuYWx5dGljcy5jb22CFiouZ29vZ2xlLWFuYWx5dGljcy5jb22CCmdv 85 | b2dsZS5jb22CEmdvb2dsZWNvbW1lcmNlLmNvbYIUKi5nb29nbGVjb21tZXJjZS5j 86 | b22CCGdncGh0LmNuggoqLmdncGh0LmNuggp1cmNoaW4uY29tggwqLnVyY2hpbi5j 87 | b22CCHlvdXR1LmJlggt5b3V0dWJlLmNvbYINKi55b3V0dWJlLmNvbYIUeW91dHVi 88 | ZWVkdWNhdGlvbi5jb22CFioueW91dHViZWVkdWNhdGlvbi5jb22CD3lvdXR1YmVr 89 | aWRzLmNvbYIRKi55b3V0dWJla2lkcy5jb22CBXl0LmJlggcqLnl0LmJlghphbmRy 90 | b2lkLmNsaWVudHMuZ29vZ2xlLmNvbYIbZGV2ZWxvcGVyLmFuZHJvaWQuZ29vZ2xl 91 | LmNughxkZXZlbG9wZXJzLmFuZHJvaWQuZ29vZ2xlLmNughhzb3VyY2UuYW5kcm9p 92 | ZC5nb29nbGUuY24wIQYDVR0gBBowGDAIBgZngQwBAgEwDAYKKwYBBAHWeQIFAzA8 93 | BgNVHR8ENTAzMDGgL6AthitodHRwOi8vY3Jscy5wa2kuZ29vZy9ndHMxYzMvUU92 94 | SjBOMXNUMkEuY3JsMIIBBAYKKwYBBAHWeQIEAgSB9QSB8gDwAHcARJRlLrDuzq/E 95 | QAfYqP4owNrmgr7YyzG1P9MzlrW2gagAAAF73QViLQAABAMASDBGAiEArWffq368 96 | tzMiCHLl+A1BFjfaVIJORVMn4o43ejqiCToCIQC2XB2yUfqlhx8t70bRv9PsrATA 97 | VJeG4w1NoCvspRpCnAB1APZclC/RdzAiFFQYCDCUVo7jTRMZM7/fDC8gC8xO8WTj 98 | AAABe90FYRMAAAQDAEYwRAIgAZcPBI5OJaZQHgCD2qkmRAWyE3G60hQklI3psMyA 99 | yaICIAvd8zNVImiwu5RRhKkJ2c6sI9RABL43P9+cj0Qxddk8MA0GCSqGSIb3DQEB 100 | CwUAA4IBAQCTyIgyrPBdskJmSjsTLl6Dbe8Z9NuUCsqlL4t2L6MrZECzMxKag2H9 101 | pFdhSbQxjwdySgTwXWfVcAfuWxOw3qIrClr47G//aBN1m+Q35I73V3Ya16LKdoNm 102 | 3CLGe6qMArlBAg86q0Sr72OeZVKRuTya7l7wHRAMK1+nGCv5Acc+75q/HKj1OkVV 103 | njIG2whCZ+G5LmYZmKroEXIBUna3MGijHrlq58tFgQUSVQqVQzU2tseLIBvz284r 104 | iarLqQ7sR3xVM76Qgl+Be4A4z4fE7Dz1zRIbnetKn8YO5SO/B/H91EeIB4q+nmRO 105 | tYxFcW8qt9iyYP/rqp2q6lBmzkPLEpJH 106 | -----END CERTIFICATE----- 107 | -------------------------------------------------------------------------------- /utils/check_deps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # colors 4 | RED='\033[0;31m' 5 | GREEN='\033[0;32m' 6 | YELLOW='\033[0;33m' 7 | NC='\033[0m' # No Color 8 | 9 | FAILED= 10 | 11 | check_required() { 12 | 13 | printf "Checking %35s:" "$1" 14 | 15 | PROG=$(command -v "$1" 2>/dev/null) 16 | 17 | if [ -z "${PROG}" ]; then 18 | ERROR="$1 not found" 19 | printf " [${RED}error${NC}: %-35s]\n" "${ERROR}" 20 | FAILED=1 21 | else 22 | printf " [${GREEN}OK${NC}: %-35s]\n" "${PROG}" 23 | fi 24 | 25 | } 26 | 27 | check_optional() { 28 | 29 | printf "Checking %35s:" "$1" 30 | 31 | PROG=$(command -v "$1" 2>/dev/null) 32 | 33 | if [ -z "${PROG}" ]; then 34 | ERROR="$1 not found" 35 | printf " [${YELLOW}error${NC}: %-35s]\n" "${ERROR}" 36 | else 37 | printf " [${GREEN}OK${NC}: %-35s]\n" "${PROG}" 38 | fi 39 | 40 | } 41 | 42 | printf "\nChecking required dependencies:\n\n" 43 | 44 | check_required bc 45 | check_required curl 46 | check_required date 47 | check_required file 48 | check_required host 49 | check_required nmap 50 | check_required openssl 51 | 52 | printf "\nChecking optional dependencies:\n\n" 53 | 54 | check_optional bzip2 55 | check_optional dig 56 | check_optional expand 57 | check_optional expect 58 | check_optional gmake 59 | check_optional ifconfig 60 | check_optional ip 61 | check_optional java 62 | check_optional netcat 63 | check_optional python3 64 | check_optional tar 65 | 66 | printf "\nChecking optional dependencies for development:\n\n" 67 | 68 | check_optional dig 69 | check_optional shellcheck 70 | check_optional shfmt 71 | check_optional shunit2 72 | check_optional tinyproxy 73 | 74 | 75 | if [ -n "${FAILED}" ] ; then 76 | exit 1 77 | fi 78 | 79 | exit 0 80 | -------------------------------------------------------------------------------- /utils/check_documentation.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ERROR=0 4 | 5 | # get the help 6 | HELP=$(./check_ssl_cert --help) 7 | 8 | # check for lines that are too long (78 chars) 9 | LONG_LINES=$(echo "${HELP}" | perl -ne 'length ($_) > 78 && print') 10 | 11 | if [ -n "${LONG_LINES}" ]; then 12 | echo "Help lines are too long (>78 chars)" 13 | echo "${LONG_LINES}" 14 | ERROR=1 15 | fi 16 | 17 | ALL_OPTIONS=$( cat utils/help.txt utils/deprecated.txt ) 18 | 19 | # list all the command line options 20 | 21 | # shellcheck disable=SC2013 22 | for option in $(grep '^[ ]*-.*)$' check_ssl_cert | sed -e 's/^[ ]*//' -e 's/)//'); do 23 | 24 | case "${option}" in 25 | '|' | '--' | '-*') 26 | continue 27 | ;; 28 | *) 29 | 30 | # check if the option is documented in the help.txt file 31 | if ! echo "${ALL_OPTIONS}" | grep -q -- "${option}"; then 32 | echo "Error: '${option}' is not documented in help.txt or deprecated.txt" 33 | ERROR=1 34 | fi 35 | 36 | # check if the option is documented in check_ssl_cert 37 | if ! echo "${HELP}" | grep -q -- "${option}"; then 38 | echo "Error: '${option}' is not documented in the help (--help)" 39 | ERROR=1 40 | fi 41 | 42 | # check if the option is documented in README.md 43 | if ! grep -q -- "${option}" README.md; then 44 | echo "Error: '${option}' is not documented in README.md" 45 | ERROR=1 46 | fi 47 | 48 | # check if the option is documented in the man page 49 | if ! grep -q -- "${option}" check_ssl_cert.1; then 50 | echo "Error: '${option}' is not documented in check_ssl_cert.1" 51 | ERROR=1 52 | fi 53 | 54 | ;; 55 | 56 | esac 57 | 58 | done 59 | 60 | # che the Icigna conf file (only long options not deprecated) 61 | 62 | # shellcheck disable=SC2013 63 | for option in $(sed -e 's/;.*//' -e 's/.*,//' -e 's/[ ].*//' utils/help.txt | sort -u ); do 64 | 65 | case "${option}" in 66 | '|' | '--' | '-*' | '--version' | '-?') 67 | continue 68 | ;; 69 | *) 70 | 71 | # check if the option is documented in the check_ssl_cert_icinga2.conf file 72 | if ! grep -q -- "${option}" check_ssl_cert_icinga2.conf; then 73 | echo "Error: ${option} is not documented in check_ssl_cert_icinga2.conf" 74 | ERROR=1 75 | fi 76 | ;; 77 | 78 | esac 79 | 80 | done 81 | 82 | # check if the option descriptions are present in all the files 83 | 84 | while read -r line; do 85 | 86 | option=$(echo "${line}" | sed 's/;.*//') 87 | description=$(echo "${line}" | sed 's/[^;]*;//') 88 | 89 | if ! grep -q -- "${description}" check_ssl_cert; then 90 | echo "Error: the description of option '${option}' '${description}' is not present in check_ssl_cert" 91 | ERROR=1 92 | fi 93 | 94 | if ! grep -q -- "${description}" check_ssl_cert.1; then 95 | # check for automatically generated options 96 | # shellcheck disable=SC2016 97 | if ! echo "${description}" | grep -q '${'; then 98 | echo "Error: the description of option '${option}' '${description}' is not present in check_ssl_cert.1" 99 | ERROR=1 100 | fi 101 | fi 102 | 103 | if ! grep -q -- "${description}" README.md; then 104 | # check for automatically generated options 105 | # shellcheck disable=SC2016 106 | if ! echo "${description}" | grep -q '${'; then 107 | echo "Error: the description of option '${option}' '${description}' is not present in README.md" 108 | ERROR=1 109 | fi 110 | fi 111 | 112 | done < utils/help.txt 113 | 114 | exit "${ERROR}" 115 | -------------------------------------------------------------------------------- /utils/deprecated.txt: -------------------------------------------------------------------------------- 1 | --altnames;Match the pattern specified in -n with 2 | --altnames;alternate names too (enabled by default) 3 | --crl;Check revocation via CRL (enabled by 4 | --crl;default) 5 | --curl-user-agent string;User agent that curl shall use to obtain 6 | --curl-user-agent string;the issuer cert 7 | --days days;(see --critical and --warning) 8 | --days days;Minimum number of days a certificate has 9 | --days days;to be valid 10 | --no_ssl2;Disable SSLv2 (deprecated use --no-ssl2) 11 | --no_ssl3;Disable SSLv3 (deprecated use --no-ssl3) 12 | --no_tls1;Disable TLSv1 (deprecated use --no-tls1) 13 | --no_tls1_1;--no-tls1_1) 14 | --no_tls1_1;Disable TLSv1.1 (deprecated use 15 | --no_tls1_2;--no-tls1_2) 16 | --no_tls1_2;Disable TLSv1.1 (deprecated use 17 | --no_tls1_3;--no-tls1_3) 18 | --no_tls1_3;Disable TLSv1.1 (deprecated use 19 | --ocsp;Check revocation via OCSP (enabled by 20 | --ocsp;default) 21 | --require-hsts;Require HTTP Strict Transport Security- 22 | --require-san;Alternative Name 23 | --require-san;Require the presence of a Subject 24 | --require-san;extension 25 | --require-security-header header;Require the specified HTTP 26 | --require-security-header header;security header (e.g., X-Frame-Options) 27 | --require-security-headers-path path;security headers 28 | --require-security-headers-path path;the path to be used to fetch HTTP 29 | --require-security-headers; Content-Security-Policy 30 | --require-security-headers; Permissions-Policy 31 | --require-security-headers; Referrer-Policy 32 | --require-security-headers; X-Content-Type-Options 33 | --require-security-headers; X-Frame-Options 34 | --require-security-headers; strict-transport-security 35 | --require-security-headers;Require all the HTTP security headers: 36 | --require-x-frame-options [path];'path' is the optional path to be used 37 | --require-x-frame-options [path];Require the presence of the 38 | --require-x-frame-options [path];X-Frame-Options HTTP header 39 | --require-x-frame-options [path];in the URL to check for the header 40 | -N,--host-cn;(enabled by default) 41 | -N,--host-cn;Match CN with the host name 42 | -S,--ssl version;(see: --ssl2 or --ssl3) 43 | -S,--ssl version;Force SSL version (2,3) 44 | -n,--cn name;(can be specified multiple times) 45 | -n,--cn name;Pattern to match the CN or AltName 46 | -------------------------------------------------------------------------------- /utils/help.txt: -------------------------------------------------------------------------------- 1 | --all-local;(without SSL-Labs) 2 | --all-local;Enable all the possible optional checks 3 | --all-local;at the maximum level 4 | --all;Enable all the possible optional checks 5 | --all;at the maximum level 6 | --allow-empty-san;Allow certificates without Subject 7 | --allow-empty-san;Alternative Names (SANs) 8 | --check-chain;The certificate chain cannot contain 9 | --check-chain;double or root certificates 10 | --check-ciphers grade;Check the offered ciphers 11 | --check-ciphers-warnings;Critical if nmap reports a warning for an 12 | --check-ciphers-warnings;offered cipher 13 | --check-http-headers;Check the HTTP headers for best practices 14 | --check-ssl-labs-warn grade;SSL Labs grade on which to warn 15 | --clientpass phrase;Set passphrase for client certificate. 16 | --configuration file;Read options from the specified file 17 | --curl-bin path;Path of the curl binary to be used 18 | --custom-http-header string;Custom HTTP header sent when getting the 19 | --custom-http-header string;cert example: 'X-Check-Ssl-Cert: Foobar=1' 20 | --dane 211;SHA2-256(1) TLSA record exists 21 | --dane 211;Verify that a valid DANE-TA(2) SPKI(1) 22 | --dane 301;SHA2-256(1) TLSA record exists 23 | --dane 301;Verify that a valid DANE-EE(3) Cert(0) 24 | --dane 302;SHA2-512(2) TLSA record exists 25 | --dane 302;Verify that a valid DANE-EE(3) Cert(0) 26 | --dane 311;SHA2-256(1) TLSA record exists 27 | --dane 311;Verify that a valid DANE-EE(3) SPKI(1) 28 | --dane 312;SHA2-512(1) TLSA record exists 29 | --dane 312;Verify that a valid DANE-EE(3) SPKI(1) 30 | --dane;(since OpenSSL 1.1.0) 31 | --dane;Verify that valid DANE records exist 32 | --date path;Path of the date binary to be used 33 | --debug-cert;Store the retrieved certificates in the 34 | --debug-cert;current directory 35 | --debug-file file;Write the debug messages to file 36 | --debug-headers;Store the retrieved HTLM headers in the 37 | --debug-headers;headers.txt file 38 | --debug-time;Write timing information in the 39 | --debug-time;debugging output 40 | --default-format;Print the default output format and exit 41 | --dig-bin path;Path of the dig binary to be used 42 | --do-not-resolve;Do not check if the host can be resolved 43 | --dtls1;Use the DTLS protocol 1.0 44 | --dtls1_2;Use the DTLS protocol 1.2 45 | --dtls;Use the DTLS protocol 46 | --ecdsa;Signature algorithm selection: force ECDSA 47 | --ecdsa;certificate 48 | --element number;Check up to the N cert element from the 49 | --element number;beginning of the chain 50 | --file-bin path;Path of the file binary to be used 51 | --fingerprint hash;Pattern to match the fingerprint 52 | --fingerprint-alg algorithm;Algorithm for fingerprint. Default sha1 53 | --first-element-only;Verify just the first cert element, not 54 | --first-element-only;the whole chain 55 | --force-dconv-date;Force the usage of dconv for date 56 | --force-dconv-date;computations 57 | --force-perl-date;Force the usage of Perl for date 58 | --force-perl-date;computations 59 | --format FORMAT;%CA_ISSUER_MATCHED%' 60 | --format FORMAT;Format output template on success, for 61 | --format FORMAT;example: '%SHORTNAME% OK %CN% from 62 | --grep-bin path;Path of the grep binary to be used 63 | --http-headers-path path;The path to be used to fetch HTTP headers 64 | --http-use-get;HTTP related checks 65 | --http-use-get;Use GET instead of HEAD (default) for the 66 | --ignore-altnames;Ignore alternative names when matching 67 | --ignore-altnames;pattern specified in -n (or the host name) 68 | --ignore-crl;Ignore CRLs 69 | --ignore-connection-problems [state];In case of connection problems 70 | --ignore-connection-problems [state];returns OK or the optional state 71 | --ignore-dh;Ignore too small DH keys 72 | --ignore-exp;Ignore expiration date 73 | --ignore-host-cn;Do not complain if the CN does not match 74 | --ignore-host-cn;the host name 75 | --ignore-http-headers;Ignore checks on HTTP headers with --all 76 | --ignore-http-headers;and --all-local 77 | --ignore-incomplete-chain;Do not check chain integrity 78 | --ignore-maximum-validity;Ignore the certificate maximum validity 79 | --ignore-ocsp-errors;Continue if the OCSP status cannot be 80 | --ignore-ocsp-errors;checked 81 | --ignore-ocsp-timeout;Ignore OCSP result when timeout occurs 82 | --ignore-ocsp-timeout;while checking 83 | --ignore-ocsp;Do not check revocation with OCSP 84 | --ignore-sct;Do not check for signed certificate 85 | --ignore-sct;timestamps (SCT) 86 | --ignore-sig-alg;Do not check if the certificate was signed 87 | --ignore-sig-alg;with SHA1 or MD5 88 | --ignore-ssl-labs-cache;Force a new check by SSL Labs (see -L) 89 | --ignore-ssl-labs-errors;Ignore errors if SSL Labs is not 90 | --ignore-ssl-labs-errors;accessible or times out 91 | --ignore-tls-renegotiation;Ignore the TLS renegotiation check 92 | --ignore-unexpected-eof;Ignore unclean TLS shutdowns 93 | --inetproto protocol;Force IP version 4 or 6 94 | --info;Print certificate information 95 | --init-host-cache;Initialize the host cache 96 | --issuer-cert-cache dir;Directory where to store issuer 97 | --issuer-cert-cache dir;certificates cache 98 | --jks-alias alias;(requires --file) 99 | --jks-alias alias;Alias name of the Java KeyStore entry 100 | --long-output list;'all' will include all the available 101 | --long-output list;Append the specified comma separated (no 102 | --long-output list;Valid attributes are: 103 | --long-output list;and fingerprint. 104 | --long-output list;attributes. 105 | --long-output list;enddate, startdate, subject, issuer, 106 | --long-output list;modulus, serial, hash, email, ocsp_uri 107 | --long-output list;output on additional lines 108 | --long-output list;spaces) list of attributes to the plugin 109 | --maximum-validity [days];The maximum validity of the certificate 110 | --maximum-validity [days];This check is automatic for HTTPS 111 | --maximum-validity [days];must not exceed 'days' (default 397) 112 | --nmap-bin path;Path of the nmap binary to be used 113 | --nmap-with-proxy;Allow nmap to be used with a proxy 114 | --no-perf;Do not show performance data 115 | --no-proxy-curl;Ignore the http_proxy and https_proxy 116 | --no-proxy-curl;environment variables 117 | --no-proxy-curl;for curl 118 | --no-proxy-s_client;Ignore the http_proxy and https_proxy 119 | --no-proxy-s_client;environment variables 120 | --no-proxy-s_client;for openssl s_client 121 | --no-proxy;Ignore the http_proxy and https_proxy 122 | --no-proxy;environment variables 123 | --no-ssl2;Disable SSL version 2 124 | --no-ssl3;Disable SSL version 3 125 | --no-tls1;Disable TLS version 1 126 | --no-tls1_1;Disable TLS version 1.1 127 | --no-tls1_2;Disable TLS version 1.2 128 | --no-tls1_3;Disable TLS version 1.3 129 | --not-issued-by issuer;Check that the issuer of the certificate 130 | --not-issued-by issuer;does not match the given pattern 131 | --not-valid-longer-than days;Critical if the certificate validity is 132 | --not-valid-longer-than days;longer than the specified period 133 | --ocsp-critical hours;Minimum number of hours an OCSP response 134 | --ocsp-critical hours;has to be valid to issue a critical status 135 | --ocsp-warning hours;Minimum number of hours an OCSP response 136 | --ocsp-warning hours;has to be valid to issue a warning status 137 | --openssl path;Path of the openssl binary to be used 138 | --password source;Password source for a local certificate, 139 | --password source;openssl(1) 140 | --password source;see the PASS PHRASE ARGUMENTS section 141 | --path path;Set the PATH variable to 'path' 142 | --precision digits;Number of decimal places for durations: 143 | --precision digits;defaults to 0 if critical or warning are 144 | --precision digits;integers, 2 otherwise 145 | --prometheus;Generate Prometheus/OpenMetrics output 146 | --proxy proxy;Set http_proxy and the s_client -proxy 147 | --proxy proxy;option 148 | --python-bin path;Path of the python binary to be used 149 | --require-client-cert [list]; certificate CAs 150 | --require-client-cert [list];The server must accept a client 151 | --require-client-cert [list];certificate. 'list' is an optional comma 152 | --require-client-cert [list];separated list of expected client 153 | --require-dnssec;Require DNSSEC 154 | --require-http-header header;(e.g., strict-transport-security) 155 | --require-http-header header;Require the specified HTTP header 156 | --require-no-http-header header;HTTP header (e.g., X-Powered-By) 157 | --require-no-http-header header;Require the absence of the specified 158 | --require-no-ssl2;Critical if SSL version 2 is offered 159 | --require-no-ssl3;Critical if SSL version 3 is offered 160 | --require-no-tls1;Critical if TLS 1 is offered 161 | --require-no-tls1_1;Critical if TLS 1.1 is offered 162 | --require-no-tls1_2;Critical if TLS 1.2 is offered 163 | --require-ocsp-stapling;Require OCSP stapling 164 | --require-purpose usage;Require the specified key usage (can be 165 | --require-purpose usage;specified more then once) 166 | --require-purpose-critical;The key usage must be critical 167 | --resolve ip;Provide a custom IP address for the 168 | --resolve ip;specified host 169 | --resolve-over-http [server];Resolve the host over HTTP using Google or 170 | --resolve-over-http [server];the specified server 171 | --rootcert-dir path;Root directory to be used for 172 | --rootcert-dir path;certificate validation 173 | --rootcert-file path;Root certificate to be used for 174 | --rootcert-file path;certificate validation 175 | --rsa;Signature algorithm selection: force RSA 176 | --rsa;certificate 177 | --security-level number;See SSL_CTX_set_security_level(3) for a 178 | --security-level number;Set the security level to specified value 179 | --security-level number;description of what each level means 180 | --serial serialnum;Pattern to match the serial number 181 | --skip-element number;Skip checks on the Nth cert element (can 182 | --skip-element number;be specified multiple times) 183 | --sni name;'name' 184 | --sni name;Set the TLS SNI (Server Name Indication) 185 | --sni name;extension in the ClientHello message to 186 | --ssl2;Force SSL version 2 187 | --ssl3;Force SSL version 3 188 | --temp dir;Directory where to store the temporary 189 | --temp dir;files 190 | --terse;Terse output 191 | --tls1;Force TLS version 1 192 | --tls1_1;Force TLS version 1.1 193 | --tls1_2;Force TLS version 1.2 194 | --tls1_3;Force TLS version 1.3 195 | --user-agent string;User agent that shall be used for HTTPS 196 | --user-agent string;connections 197 | --quic;Use QUIC 198 | --xmpphost name;Specify the host for the 'to' attribute 199 | --xmpphost name;of the stream element 200 | -4;Force IPv4 201 | -6;Force IPv6 202 | -A,--noauth;Ignore authority warnings (expiration 203 | -A,--noauth;only) 204 | -C,--clientcert path;Use client certificate to authenticate 205 | -H,--host host;Server 206 | -K,--clientkey path;Use client certificate key to authenticate 207 | -L,--check-ssl-labs grade;(please check 208 | -L,--check-ssl-labs grade;SSL Labs assessment 209 | -L,--check-ssl-labs grade;https://www.ssllabs.com/about/terms.html) 210 | -P,--protocol protocol;Use the specific protocol: 211 | -P,--protocol protocol;dns, ftp, ftps, http, https (default), 212 | -P,--protocol protocol;h2 (HTTP/2), h3 (HTTP/3), imap, imaps, 213 | -P,--protocol protocol;irc, ircs, ldap, ldaps, mqtts, mysql, 214 | -P,--protocol protocol;pop3, pop3s, postgres, sieve, sips, smtp, 215 | -P,--protocol protocol;smtps, tds, xmpp, xmpp-server. 216 | -P,--protocol protocol;ftp, imap, irc, ldap, pop3, postgres, 217 | -P,--protocol protocol;sieve, smtp: switch to TLS using StartTLS 218 | -V,--version;version 219 | -c,--critical days;Can be a floating point number, e.g., 0.5 220 | -c,--critical days;Default: ${CRITICAL_DAYS} 221 | -c,--critical days;Minimum number of days a certificate has 222 | -c,--critical days;to be valid to issue a critical status. 223 | -d,--debug;Produce debugging output (can be 224 | -d,--debug;specified more than once) 225 | -e,--email address;Pattern (extended regular expression) to 226 | -e,--email address;match the email address contained in the 227 | -e,--email address;certificate. You can specify different 228 | -e,--email address;addresses separated by a pipe 229 | -e,--email address;(e.g., 'addr1|addr2') 230 | -f,--file file;Local file path or URI. 231 | -f,--file file;With -f you can not only pass a x509 232 | -f,--file file;certificate file but also a certificate 233 | -f,--file file;revocation list (CRL) to check the 234 | -f,--file file;validity period or a Java KeyStore file 235 | -h,--help,-?;This help message 236 | -i,--issuer issuer;Pattern (extended regular expression) to 237 | -i,--issuer issuer;match the issuer of the certificate 238 | -i,--issuer issuer;You can specify different issuers 239 | -i,--issuer issuer;separated by a pipe 240 | -m,--match name;(can be specified multiple times) 241 | -m,--match name;Pattern to match the CN or AltName 242 | -o,--org org;Pattern to match the organization of the 243 | -o,--org org;certificate 244 | -p,--port port;TCP port (default 443) 245 | -q,--quiet;Do not produce any output 246 | -r,--rootcert path;Root certificate or directory to be used 247 | -r,--rootcert path;for certificate validation 248 | -s,--selfsigned;Allow self-signed certificates 249 | -t,--timeout seconds;(defaults to ${TIMEOUT} seconds) 250 | -t,--timeout seconds;Timeout after the specified time 251 | -u,--url URL;HTTP request URL 252 | -v,--verbose;Verbose output (can be specified more than 253 | -v,--verbose;once) 254 | -w,--warning days;Can be a floating point number, e.g., 0.5 255 | -w,--warning days;Default: ${WARNING_DAYS}" 256 | -w,--warning days;Minimum number of days a certificate has 257 | -w,--warning days;to be valid to issue a warning status. 258 | -------------------------------------------------------------------------------- /utils/prepare_rpm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "Building the RPMs" 4 | OUT=$(make rpm 2>&1 | grep ^Wrote) 5 | 6 | echo "${OUT}" 7 | 8 | RPM=$(echo "${OUT}" | grep /RPMS | grep -v debug | sed 's/.* //') 9 | SRPM=$(echo "${OUT}" | grep SRPMS | sed 's/.* //') 10 | 11 | echo "RPM: ${RPM}" 12 | echo "SRPM: ${SRPM}" 13 | 14 | ARCH=$(echo "${RPM}" | sed 's/\.rpm$//' | sed 's/.*\.//') 15 | DIST=$(echo "${SRPM}" | sed 's/\.src\.rpm$//' | sed 's/.*\.//') 16 | 17 | echo "arch: ${ARCH}" 18 | echo "dist: ${DIST}" 19 | 20 | WEBROOT=/var/www/rpm 21 | case ${DIST} in 22 | fc30) 23 | RPMDIR="${WEBROOT}/fedora/30/${ARCH}" 24 | SRPMDIR="${WEBROOT}/fedora/30/SRPMS" 25 | DIST='fedora' 26 | RELEASE='30' 27 | ;; 28 | fc31) 29 | RPMDIR="${WEBROOT}/fedora/31/${ARCH}" 30 | SRPMDIR="${WEBROOT}/fedora/31/SRPMS" 31 | DIST='fedora' 32 | RELEASE='31' 33 | ;; 34 | fc32) 35 | RPMDIR="${WEBROOT}/fedora/32/${ARCH}" 36 | SRPMDIR="${WEBROOT}/fedora/32/SRPMS" 37 | DIST='fedora' 38 | RELEASE='32' 39 | ;; 40 | fc33) 41 | RPMDIR="${WEBROOT}/fedora/33/${ARCH}" 42 | SRPMDIR="${WEBROOT}/fedora/33/SRPMS" 43 | DIST='fedora' 44 | RELEASE='33' 45 | ;; 46 | fc34) 47 | RPMDIR="${WEBROOT}/fedora/34/${ARCH}" 48 | SRPMDIR="${WEBROOT}/fedora/34/SRPMS" 49 | DIST='fedora' 50 | RELEASE='34' 51 | ;; 52 | fc35) 53 | RPMDIR="${WEBROOT}/fedora/35/${ARCH}" 54 | SRPMDIR="${WEBROOT}/fedora/35/SRPMS" 55 | DIST='fedora' 56 | RELEASE='35' 57 | ;; 58 | fc36) 59 | RPMDIR="${WEBROOT}/fedora/36/${ARCH}" 60 | SRPMDIR="${WEBROOT}/fedora/36/SRPMS" 61 | DIST='fedora' 62 | RELEASE='36' 63 | ;; 64 | fc37) 65 | RPMDIR="${WEBROOT}/fedora/37/${ARCH}" 66 | SRPMDIR="${WEBROOT}/fedora/37/SRPMS" 67 | DIST='fedora' 68 | RELEASE='37' 69 | ;; 70 | fc38) 71 | RPMDIR="${WEBROOT}/fedora/38/${ARCH}" 72 | SRPMDIR="${WEBROOT}/fedora/38/SRPMS" 73 | DIST='fedora' 74 | RELEASE='38' 75 | ;; 76 | fc39) 77 | RPMDIR="${WEBROOT}/fedora/39/${ARCH}" 78 | SRPMDIR="${WEBROOT}/fedora/39/SRPMS" 79 | DIST='fedora' 80 | RELEASE='39' 81 | ;; 82 | fc40) 83 | RPMDIR="${WEBROOT}/fedora/40/${ARCH}" 84 | SRPMDIR="${WEBROOT}/fedora/40/SRPMS" 85 | DIST='fedora' 86 | RELEASE='40' 87 | ;; 88 | fc41) 89 | RPMDIR="${WEBROOT}/fedora/41/${ARCH}" 90 | SRPMDIR="${WEBROOT}/fedora/41/SRPMS" 91 | DIST='fedora' 92 | RELEASE='41' 93 | ;; 94 | fc42) 95 | RPMDIR="${WEBROOT}/fedora/42/${ARCH}" 96 | SRPMDIR="${WEBROOT}/fedora/42/SRPMS" 97 | DIST='fedora' 98 | RELEASE='42' 99 | ;; 100 | el7) 101 | RPMDIR="${WEBROOT}/epel/7/${ARCH}" 102 | SRPMDIR="${WEBROOT}/epel/7/SRPMS" 103 | DIST='epel' 104 | RELEASE='7' 105 | ;; 106 | el8) 107 | RPMDIR="${WEBROOT}/epel/8/${ARCH}" 108 | SRPMDIR="${WEBROOT}/epel/8/SRPMS" 109 | DIST='epel' 110 | RELEASE='8' 111 | ;; 112 | *) 113 | echo "Unknown distribution ${DIST}" 1>&2 114 | exit 1 115 | ;; 116 | esac 117 | 118 | echo "RPMDIR: ${RPMDIR}" 119 | echo "SRPMDIR: ${SRPMDIR}" 120 | echo "RPM: ${RPM}" 121 | echo "SRPM: ${SRPM}" 122 | echo "DIST: ${DIST}" 123 | echo "RELEASE: ${RELEASE}" 124 | 125 | export RPMDIR 126 | export SRPMDIR 127 | export RPM 128 | export SRPM 129 | export DIST 130 | export RELEASE 131 | -------------------------------------------------------------------------------- /utils/publish_release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | VERSION=$(head -n 1 VERSION) 4 | 5 | echo "Publishing release ${VERSION}" 6 | 7 | echo 8 | 9 | echo 'Checking release date' 10 | 11 | MONTH_YEAR=$(date +"%B, %Y") 12 | YEAR=$(date +"%Y") 13 | 14 | if ! grep -q "${MONTH_YEAR}" check_ssl_cert.1; then 15 | echo "Please update the date in check_ssl_cert.1" 16 | exit 1 17 | fi 18 | if ! grep -q "© Matteo Corti, 2007-${YEAR}" README.md; then 19 | echo "Please update the copyright year in README.md" 20 | exit 1 21 | fi 22 | if ! grep -q "Copyright © 2007-${YEAR} Matteo Corti" COPYRIGHT.md; then 23 | echo "Please update the copyright year in COPYRIGHT.md" 24 | exit 1 25 | fi 26 | if ! grep -q "Copyright (c) 2007-${YEAR} Matteo Corti " check_ssl_cert; then 27 | echo "Please update the copyright year in check_ssl_cert" 28 | exit 1 29 | fi 30 | echo "Copyright year check: OK" 31 | 32 | echo 33 | echo 'RELEASE_NOTES.md:' 34 | echo '------------------------------------------------------------------------------' 35 | 36 | cat RELEASE_NOTES.md 37 | 38 | echo '------------------------------------------------------------------------------' 39 | 40 | echo 'Did you update the RELEASE_NOTES.md file? ' 41 | read -r ANSWER 42 | if [ "${ANSWER}" = "y" ]; then 43 | make dist 44 | gh release create "v${VERSION}" --title "check_ssl_cert-${VERSION}" --notes-file RELEASE_NOTES.md "check_ssl_cert-${VERSION}.tar.gz" "check_ssl_cert-${VERSION}.tar.bz2" 45 | 46 | fi 47 | 48 | # get the new tag 49 | git pull 50 | -------------------------------------------------------------------------------- /utils/start_proxy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | error() { 4 | 5 | message=$1 6 | 7 | echo "Error: ${message}" 1>&2 8 | exit 1 9 | 10 | } 11 | 12 | ################################################################################ 13 | # Checks if a given program is available and executable 14 | # Params 15 | # $1 program name 16 | # Returns 1 if the program exists and is executable 17 | check_required_prog() { 18 | 19 | PROG=$(command -v "$1" 2>/dev/null) 20 | 21 | if [ -z "${PROG}" ]; then 22 | error "cannot find program: $1" 23 | fi 24 | 25 | if [ ! -x "${PROG}" ]; then 26 | error "${PROG} is not executable" 27 | fi 28 | 29 | } 30 | 31 | check_required_prog tinyproxy 32 | 33 | conf=$1 34 | 35 | if [ -z "${conf}" ]; then 36 | error "No configuration file specified" 37 | fi 38 | if ! [ -f "${conf}" ]; then 39 | error "Configuration file ${conf} is not readable" 40 | fi 41 | 42 | tinyproxy -c "${conf}" > /dev/null 2>&1 43 | -------------------------------------------------------------------------------- /utils/stats.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # authors 4 | authors=$(grep -c 'Many thanks' AUTHORS.md) 5 | 6 | # versions 7 | versions=$(grep -c Version NEWS.md) 8 | 9 | version=$(head -n 1 VERSION) 10 | 11 | PROG=$(command -v gh 2>/dev/null) 12 | 13 | if [ -z "${PROG}" ]; then 14 | echo "cannot find gh" 1>&2 15 | exit 1 16 | fi 17 | 18 | echo 19 | printf '\tcheck_ssl_cert version %s\n' "${version}" 20 | echo 21 | 22 | echo "------------------------------------------------------------------------------" 23 | echo "-- Version History and Authors" 24 | echo 25 | 26 | printf "Authors:\\t\\t%'10d\\n" "${authors}" 27 | printf "Versions:\\t\\t%'10d\\n" "${versions}" 28 | 29 | releases=$(gh release list -L 1000 | wc -l) 30 | printf "GH releases:\\t\\t%'10d\\n" "${releases}" 31 | 32 | echo 33 | 34 | echo "------------------------------------------------------------------------------" 35 | echo "-- Code" 36 | echo 37 | 38 | make distclean >/dev/null 39 | cloc --quiet . | grep -v AlDanial 40 | 41 | echo 42 | 43 | loc=$(grep -c '.' check_ssl_cert) 44 | 45 | printf "Script LoC:\\t\\t%'10d\\n" "${loc}" 46 | echo 47 | 48 | echo "------------------------------------------------------------------------------" 49 | echo "-- Repository" 50 | echo 51 | 52 | commits=$(git log --oneline | wc -l) 53 | 54 | printf "Commits:\\t\\t%'10d\\n" "${commits}" 55 | git log --numstat --format="" | awk '{files += 1}{ins += $1}{del += $2} END{printf "File changes:\t\t%10'"'"'d\nInsertions:\t\t%10'"'"'d\nDeletions:\t\t%10'"'"'d\n", files, ins, del}' 56 | 57 | open_issues=$(gh issue list -L 1000 | wc -l) 58 | closed_issues=$(gh issue list -s closed -L 1000 | wc -l) 59 | open_bugs=$(gh issue list -L 1000 -l bug | grep -v -c 'No issue match') 60 | 61 | echo 62 | printf "Open issues:\\t\\t%'10d\\n" "${open_issues}" 63 | printf "Open bugs:\\t\\t%'10d\\n" "${open_bugs}" 64 | printf "Closed issues:\\t\\t%'10d\\n" "${closed_issues}" 65 | 66 | open_prs=$(gh pr list -L 1000 | wc -l) 67 | closed_prs=$(gh pr list -s all -L 1000 | wc -l) 68 | 69 | echo 70 | printf "Open pull requests:\\t%'10d\\n" "${open_prs}" 71 | printf "Total pull requests:\\t%'10d\\n" "${closed_prs}" 72 | 73 | echo 74 | 75 | echo "------------------------------------------------------------------------------" 76 | echo "-- Features" 77 | echo 78 | 79 | command_line_options=$(sed 's/;.*//' utils/help.txt utils/deprecated.txt | sort | uniq | wc -l) 80 | printf "Command line options:\\t%'10d\\n" "${command_line_options}" 81 | 82 | echo 83 | 84 | echo "------------------------------------------------------------------------------" 85 | echo "-- Tests" 86 | echo 87 | 88 | LIST_LIMIT=10000 89 | 90 | # in_progewss 91 | # success 92 | # failure 93 | 94 | tests=$(cat test/unit_tests.sh test/integration_tests.sh | grep -c '^test') 95 | workflows=$(gh workflow list -L "${LIST_LIMIT}" | wc -l) 96 | 97 | # cache the result 98 | 99 | RUNS=$(gh run list -L "${LIST_LIMIT}") 100 | 101 | runs=$(echo "${RUNS}" | wc -l) 102 | 103 | runs_in_progress=$(echo "${RUNS}" | grep -c in_progress) 104 | runs_success=$(echo "${RUNS}" | grep -c success) 105 | runs_failure=$(echo "${RUNS}" | grep -c failure) 106 | runs_cancelled=$(echo "${RUNS}" | grep -c cancelled) 107 | 108 | printf "Tests:\\t\\t\\t%'10d\\n" "${tests}" 109 | printf "GH workflows:\\t\\t%'10d\\n" "${workflows}" 110 | printf "GH runs:\\t\\t%'10d\\n" "${runs}" 111 | printf " running:\\t\\t%'10d\\n" "${runs_in_progress}" 112 | printf " failed:\\t\\t%'10d\\n" "${runs_failure}" 113 | printf " ok:\\t\\t\\t%'10d\\n" "${runs_success}" 114 | printf " cancelled:\\t\\t%'10d\\n" "${runs_cancelled}" 115 | 116 | echo 117 | -------------------------------------------------------------------------------- /utils/update_citation.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | version=$(head -n 1 VERSION) 4 | 5 | dash='-' 6 | 7 | parse_name() { 8 | 9 | name="$1" 10 | 11 | # try to parse first-last name 12 | blanks=$(echo "${name}" | sed 's/[^ ]//g' | wc -m) 13 | 14 | if [ "${blanks}" -gt 2 ]; then 15 | echo "${dash} name: ${name}" >>CITATION.cff 16 | else 17 | first=$(echo "${name}" | sed -e 's/ .*//') 18 | last=$(echo "${name}" | sed -e 's/[^ ]* //') 19 | echo "${dash} family-names: \"${last}\"" >>CITATION.cff 20 | echo " given-names: \"${first}\"" >>CITATION.cff 21 | fi 22 | } 23 | 24 | # get the release date from the spec file 25 | date=$(grep '^ *\* [0-9]' NEWS.md | head -n 1 | sed -e 's/^ *\* //' -e 's/ .*//') 26 | 27 | cat <CITATION.cff 28 | cff-version: 1.2.0 29 | message: "If you use this software, please cite it as below." 30 | authors: 31 | - family-names: "Corti" 32 | given-names: "Matteo" 33 | orcid: "https://orcid.org/0000-0002-1746-1108" 34 | EOT 35 | 36 | grep '[*] Many thanks to' AUTHORS.md | 37 | sed -e 's/^[*] Many thanks to //' -e 's/ for.*//' | 38 | sort -d | 39 | uniq | 40 | while IFS= read -r line; do 41 | 42 | if echo "${line}" | grep -q '^\['; then 43 | 44 | # GitHub Link 45 | 46 | user=$(echo "${line}" | sed -e 's/^\[//' -e 's/\].*//') 47 | url=$(echo "${line}" | sed -e 's/^.*(//' -e 's/).*//') 48 | 49 | if echo "${user}" | grep -q '[ ]'; then 50 | # most likely a name 51 | parse_name "${user}" 52 | 53 | else 54 | echo "${dash} name: ${user}" >>CITATION.cff 55 | fi 56 | 57 | echo " website: ${url}" >>CITATION.cff 58 | 59 | else 60 | 61 | parse_name "${line}" 62 | 63 | fi 64 | 65 | done 66 | 67 | cat <>CITATION.cff 68 | title: "check_ssl_cert" 69 | version: ${version} 70 | date-released: ${date} 71 | url: "https://github.com/matteocorti/check_ssl_cert" 72 | repository-code: "https://github.com/matteocorti/check_ssl_cert" 73 | keywords: 74 | - "certificate" 75 | - "openssl" 76 | - "shell-script" 77 | - "nagios-plugin" 78 | abstract: A shell script (that can be used as a Nagios/Icinga plugin) to check an SSL/TLS connection. 79 | contact: 80 | - email: matteo@corti.li 81 | family-names: Corti 82 | given-names: Matteo 83 | type: software 84 | license: GPL-3.0 85 | EOT 86 | -------------------------------------------------------------------------------- /varia/check_ssl_cert_stats.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matteocorti/check_ssl_cert/af6633dd450f14c1c725cff3ca12130d73a46e15/varia/check_ssl_cert_stats.xlsx --------------------------------------------------------------------------------