基于Go的工具来检查/验证证书(例如,作为Nagios服务检查的一部分)。

117 阅读16分钟

检查证书

基于Go的工具来检查/验证证书(例如,作为Nagios服务检查的一部分)。

概述

此版本包含用于监控/验证证书的各种工具。

工具名称状态描述
check_certs测试版用来监控证书链的Nagios插件。
lscert测试版小型CLI应用,用于生成证书元数据和过期状态的摘要。
fixsn阿尔法小型CLI应用,用于将给定的10进制序列号转换为16进制、以冒号分隔的十六进制字符串格式。
certsum阿尔法CLI应用程序用于扫描一个或多个给定的CIDR IP范围的证书,并提供一份总结报告。

check_certs

Nagios插件用于监控证书链。除了
lscert 共享的
功能外
,该应用程序还根据
证书的通用名称
可用的SAN条目之一验证所提供的主机名

这个应用程序的输出旨在提供
Nagios需要的
单行摘要
,以便快速识别问题,同时提供更长、
更详细的信息,用于电子邮件和团队通知
atc0005/send2teams

)。

lscert

小型CLI工具,用于快速审查更换证书的结果
和/或故障排除,为什么连接到支持证书的服务可能
失败。

证书元数据可以从以下方面检索。

如果通过 IP 地址指定主机,将发出警告,除非该 IP
地址在证书的 SANs 列表中。如果你

想应用主机名验证


提供一个有效的FQDN作为
服务器名称或 "dns name",

这个警告可以被忽略。

fixsn

一个小型的CLI应用程序,用于将给定的(假定的)基数10转换成基数
16,以冒号分隔的十六进制字符串,代表证书序列号。
这个项目
以前
的版本不正确地将序列号显示为基数为10的数值
,而不是基数为16、以冒号分隔的十六进制字符串。使用这个工具可以将
旧的数值一次性转换为正确的格式(例如,
文档中保持的
证书
列表)。

除非其他人发现它很有用
,否则这个工具很可能
在未来的某一天
被移除或被折叠到另一个工具中。

certsum

certsum 是一个IP范围证书扫描器的原型。这个工具目前是
"阿尔法 "级别的质量;许多暴露的标志、帮助文本和摘要输出
在以后的版本中会有很大变化。

这个工具旨在扫描一个或多个给定的IP范围,以便
为发现的证书生成一份报告,但也可以用来扫描
少至一个目标。

对于较小的IP范围来说,性能可能是可以接受的,但可以
根据需要使用速率限制调整标志(详见配置
选项
部分)来调整。目前的
默认值是为了平衡扫描速度和操作系统对
开放文件句柄数量


限制
。如果调整这个值,从小的
增量
开始
,以确定对你的环境的最佳结果。

默认的不活动超时是用来终止应用程序的,如果扫描
尝试停滞了一段指定的时间。详情见配置
选项
部分。

IP地址可以被指定为逗号分隔的值。

  • 单个IP地址
  • CIDR IP范围
  • 部分范围
    • 使用八位数范围寻址的部分实现(例如,
      192.168.2.10-15)
  • 全称域名(FQDNs)
  • 主机名**(脆弱的)**
    • 这在很大程度上取决于你的DNS配置,特别是任何
      配置的搜索列表(又称Windows
      术语
      中的DNS Suffix Search List
      )条目,用于限定短名/主机名值

支持过滤 "OK "状态的主机和证书
,以增加或减少
生成的摘要输出

中提供的信息量(尽管有限)。

提供两种摘要模式,以控制
所提供的输出中的详细程度。

特点

  • 验证证书的多种工具

    • lscert CLI工具
      • 验证指定服务使用的证书
      • 验证本地证书 "包 "或独立的叶子证书文件
    • check_cert Nagios插件
      • 验证指定服务使用的证书
      • 验证本地证书 "包 "或独立的叶子证书文件
    • certsum CLI工具
      • 生成从给定的主机(单个或
        IP地址范围、主机名或FQDNs)和端口
        发现的证书的摘要
  • 检查所提供的证书链中的所有证书的过期情况,用于
    支持证书的服务

    • 未过期
    • 即将到期"。
      • 警告阈值
      • 关键阈值
  • 根据通用名称可用的
    SANs条目
    之一验证提供的主机名
    (见配置选项

  • 可选支持对照
    所提供的列表
    验证证书上的SANs条目

    • 如果提供SKIPSANSCHECKS 关键字作为值,


      执行
      SANs条目检查
      ;这个关键字对于定义共享的Nagios
      检查命令和服务检查
      非常有用
      ,因为一些主机可能不使用
      定义有SANs条目的

      证书。

  • 详细的 "报告 "发现

    • 证书顺序
    • 证书类型
    • 状态(OK, CRITICAL, WARNING)
    • SANs条目
    • 序列号
    • 发行者
  • 可选择从目标证书启用的
    服务或文件名
    生成类似OpenSSL的文本输出

    • 感谢grantae/certinfo
  • 可选的,使用rs/zerolog 包的分级日志记录

    • JSON格式的输出(到stderr)
    • 可选择disabled,panic,fatal,error,warn,info
      默认),debugtrace
  • 可选的,用户指定的TCP连接尝试的超时值

更新日志

参见该 CHANGELOG.md文件,以了解与
本应用程序的每个版本
相关的变化
。已经合并到master
但还没有正式发布的
变化
也可以在文件中

Unreleased
部分下注明。

还提供了
一个指向自上次
正式发布
以来的Git提交历史的有用链接
,以便进一步审查。

要求

以下是一个宽松的指导原则。其他
用于构建和运行本软件库中的工具
的Go和操作系统的组合
可能有效,但没有
经过测试。

构建源代码

  • Go 1.13以上
  • GCC
    • 如果使用自定义选项进行构建(如所提供的Makefile 所示)
  • make
    • 如果使用提供的Makefile

运行

  • Windows 7, Server 2008R2或更高版本
    • 按照官方的[Go安装说明][go-docs-install]。
  • Windows 10 1909版
    • 经过测试
  • Ubuntu Linux 16.04, 18.04

安装

  1. [下载][go-docs-download] Go

  2. [安装][go-docs-install] 去

    • 注意:请特别注意以下的备注$HOME/.profile
  3. 克隆该版本

    1. cd /tmp
    2. git clone https://github.com/atc0005/check-cert
    3. cd check-cert
  4. 安装依赖项(可选)

    • 适用于Ubuntu Linux
      • sudo apt-get install make gcc
    • 适用于CentOS Linux
      • sudo yum install make gcc
    • 适用于Windows
      • 仿真环境*(更简单*)

        • 跳过所有这些,在
          Windows
          中使用默认的go build 命令进行构建
          (关于-mod=vendor 标志的使用,见下文)
        • 使用Windows Subsystem for Linux Ubuntu环境构建,只需
          从该环境中复制出Windows二进制文件
          即可
        • 如果已经运行Docker环境,使用
          已经安装
          Go
          工具链
          的容器
        • 如果已经熟悉LXD,创建一个容器,并按照
          前面给出的安装步骤安装所需的依赖
      • 本地工具*(更难)* *
        关于
        在Windows上安装make

        的  
        潜在选择  
        ,请参见  
        [参考资料](https://golangexample.com/go-based-tooling-to-check-verify-certs-e-g-as-part-of-a-nagios-service-check/references.md)  
        部分的StackOverflow问题`32127524` 链接。
        
        • 参见
          参考文献


          中的mingw-w64项目主页链接
          ,了解
          在Windows上
          安装gcc

          和相关软件包的
          选项

  5. 构建二进制文件

    • 对于当前的操作系统,明确使用
      顶级vendor 文件夹

      • go build -mod=vendor ./cmd/check_cert/
      • go build -mod=vendor ./cmd/lscert/
      • go build -mod=vendor ./cmd/fixsn/
      • go build -mod=vendor ./cmd/certsum/


      的捆绑的依赖项。

    • 适用于所有支持的平台(已安装make

      • make all
    • 在Windows上使用

      • make windows
    • 在Linux上使用

      • make linux

  6. 下面
    适用的/tmp 子目录路径中复制新编译的二进制文件
    (基于本节中的克隆说明),并在
    需要的
    地方部署

    • 如果使用Makefile
      • ,请在/tmp/check-cert/release_assets/check_cert/

    ,请在

      • /tmp/check-cert/release_assets/lscert/

    ,请在

      • /tmp/check-cert/release_assets/fixsn/
      • ,请在/tmp/check-cert/release_assets/certsum/
    • ,如果使用go build

      • 请在/tmp/check-cert/

配置选项

阈值计算

check_cert插件的行为与
check_http v2.1.2
有些不同

对于相同的WARNING

CRITICAL

阈值,该插件的触发
时间check_http
一整天

例如,如果我们使用WARNING 阈值的默认值为30天
CRITICAL 阈值为15天。

  1. 阈值的计算

    • WARNING:现在(UTC中的确切时间)+30天
    • CRITICAL:现在(UTC中的确切时间)+15天
  2. 检查证书过期日期,最开始的匹配(按
    顺序)决定服务检查的状态

    1. ,如果证书当前时间之前过期,状态为
      EXPIRED

    2. ,如果证书在CRITICAL阈值之前过期,状态

    3. CRITICAL

    4. ,如果证书WARNING阈值之前过期,状态

    5. WARNING

    1. 否则,假设证书的状态为OK

不进行四舍五入。

其他信息见GH-32。

命令行参数

  • 使用-h--help 标志来显示当前使用信息。
  • 标记为 **required**必须通过CLI标志来设置。
  • 没有标记为需要的标志是用于
    已经定义了
    有用的默认值的设置
    ,但如果需要,可以重写。

check_cert

标志需要默认值重复可能的说明
f,filename没有false没有有效的文件名字符包含一个或多个证书的PEM格式的证书文件的全称路径。
branding没有false没有branding切换品牌细节与插件状态细节的排放。该输出默认是禁用的。
h,help没有false没有h,help显示帮助文本和支持的标志列表。
v,verbose没有falsev,verbose切换详细证书元数据的排放。默认情况下,该级别的输出是禁用的。
version没有falseversion是否显示应用程序的版本,然后立即退出应用程序。
c,age-critical15正整数天数证书检查的CRITICAL 状态的阈值。如果证书在这个天数之前过期,那么服务检查将被视为处于CRITICAL 状态。
w,age-warning30没有正整数天数证书检查的WARNING 状态的阈值。如果证书在这个天数之前过期,但在age-critical 值之前没有过期,那么服务检查将被视为处于WARNING 状态。
ll,log-level没有info没有disabled,panic,fatal,error,warn,info,debugtrace日志消息优先级过滤器。具有较低级别的日志消息被忽略。
p,port没有443没有1-65535之间的正整数,包括在内远程证书启用的服务的TCP端口。这通常是443(HTTPS)或636(LDAPS)。
t,timeout没有10没有正整数秒在放弃与远程认证服务的连接尝试(为了检索证书)并返回错误之前,允许的超时值(秒)。
se,sans-entries没有没有逗号分隔的数值列表预计远程服务使用的证书的一个或多个主题替代名称(SAN)。如果提供,这个逗号分隔(可选)的值列表是证书通过验证的必要条件。如果提供了不区分大小写的SKIPSANSCHECKS关键字,则验证将被跳过,有效地将该标志的使用变成NOOP。
s,server没有全称域名或IP地址远程系统的全称域名或IP地址,其证书将被监控。该值用于与服务器建立连接,以检索证书链。对于只有一个证书的主机,这个值通常是主机本身的FQDN,但对于多证书的服务器,用户指定的值将是至关重要的,以便让远程主机选择适当的证书(支持服务器名称指示(SNI))。对于托管在这些服务器上的网站,有必要改为提供网站的FQDN而不是服务器主机名。例如,指定www.example.org ,而不是host7.example.com 。如果有疑问,请指定网站的FQDN。用户指定的值也将根据通用名称和主题替代名称字段进行验证*,除非*还指定了dns-name 标志,在这种情况下,这个值只用于建立初始连接。
dn,dns-name没有没有全称域名或IP地址远程系统的全称域名,用于主机名验证。该选项可用于初始连接使用与证书无关的名称或 IP 地址的情况。更多信息请参见server 标志描述。

lscert

标志需要默认值重复可能的说明
f,filename没有false没有有效的文件名字符包含一个或多个证书的PEM格式的证书文件的全称路径。
text没有false没有true,false切换x509 TLS证书在OpenSSL启发的文本格式中的排放。该输出在默认情况下是禁用的。
h,helpfalse没有h,help显示帮助文本和支持的标志列表。
v,verbose没有falsev,verbose切换详细证书元数据的排放。默认情况下,该级别的输出是禁用的。
version没有falseversion是否显示应用程序的版本,然后立即退出应用程序。
c,age-critical15正整数天数证书检查的CRITICAL 状态的阈值。如果证书在这个天数之前过期,那么服务检查将被视为处于CRITICAL 状态。
w,age-warning30没有正整数天数证书检查的WARNING 状态的阈值。如果证书在这个天数之前过期,但在age-critical 值之前没有过期,那么该服务检查将被视为处于WARNING 状态。
ll,log-level没有info没有disabled,panic,fatal,error,warn,info,debugtrace日志消息优先级过滤器。具有较低级别的日志消息被忽略。
p,port没有443没有1-65535之间的正整数,包括在内远程证书启用的服务的TCP端口。这通常是443(HTTPS)或636(LDAPS)。
t,timeout没有10没有正整数秒在放弃与远程认证服务的连接尝试(为了检索证书)并返回错误之前,允许的超时值(秒)。
se,sans-entries没有没有逗号分隔的数值列表预计远程服务使用的证书的一个或多个主题替代名称(SAN)。如果提供,这个逗号分隔的(可选)值列表是证书通过验证的必要条件。如果提供了不区分大小写的SKIPSANSCHECKS关键字,则验证将被跳过,有效地将该标志的使用变成NOOP。
s,server没有全称域名或IP地址远程系统的全称域名或IP地址,其证书将被监控。该值用于与服务器建立连接,以检索证书链。对于只有一个证书的主机,这个值通常是主机本身的FQDN,但对于多证书的服务器,用户指定的值将是至关重要的,以便让远程主机选择适当的证书(支持服务器名称指示(SNI))。对于托管在这些服务器上的网站,有必要改为提供网站的FQDN而不是服务器主机名。例如,指定www.example.org ,而不是host7.example.com 。如果有疑问,请指定网站的FQDN。用户指定的值也将根据通用名称和主题替代名称字段进行验证*,除非*还指定了dns-name 标志,在这种情况下,这个值只用于建立初始连接。
dn,dns-name没有没有完全合格的域名或IP地址用于主机名验证的远程系统的完全限定域名。该选项可用于初始连接使用与证书无关的名称或 IP 地址的情况。更多信息见server 标志描述。

fixsn

这个工具不接受任何标志。相反,它只希望收到一个
参数:一个基数为10的格式化证书序列号,内部处理为
*big.Int 。这个值被转换为一个以16为基数、以冒号为分隔符的十六进制
字符串。这种格式是用于检查证书的工具所共有的。

使用方法见实例部分。

certsum

这个工具正在早期开发中。这个工具的选项可能会有
变化,也许在未来的版本中会有很大的变化。

标志需要默认值重复可能的说明
h,help没有false没有h,help显示帮助文本和支持的标志列表。
version没有falseversion是否显示应用程序的版本,然后立即退出应用程序。
c,age-critical15正整数天数证书检查的CRITICAL 状态的阈值。如果证书在这个天数之前过期,那么服务检查将被视为处于CRITICAL 状态。
w,age-warning30没有正整数的天数证书检查的WARNING 状态的阈值。如果证书在这个天数之前过期,但在age-critical 值之前没有过期,那么该服务检查将被视为处于WARNING 状态。
ll,log-level没有info没有disabled,panic,fatal,error,warn,info,debugtrace日志消息优先级过滤器。具有较低级别的日志消息被忽略。
t,timeout没有10没有正整数秒在放弃与远程认证服务的连接尝试(为了检索证书)并返回错误之前,允许的超时值(秒)。
se,sans-entries没有没有逗号分隔的数值列表预计远程服务使用的证书的一个或多个主题替代名称(SAN)。如果提供,这个逗号分隔(可选)的值列表是证书通过验证的必要条件。如果提供了不区分大小写的SKIPSANSCHECKS关键字,则验证将被跳过,有效地将该标志的使用变成NOOP。
st,scan-timeout没有200没有正整数的毫秒,最小为1在端口扫描过程中的连接尝试被放弃并返回错误之前的毫秒数。这个超时值与检索证书时使用的一般timeout 值分开。这个设置是专门用来快速确定端口状态的,作为速度至关重要的批量操作的一部分。
at,app-timeout30没有正整数的秒数,最小为2允许应用程序在自动终止前保持不活动(即 "挂起")的秒数。
srl,scan-rate-limit没有100没有正整数最大并发端口和证书扫描。剩余的扫描被排队,直到现有的扫描完成。
ips,hosts没有没有一个或多个有效的、用逗号分隔的 IP 地址(单个或范围)、主机名或 FQDNs逗号分隔的单个IP地址、CIDR IP范围、部分(破折号分隔的)范围(如192.168.2.10-15)、主机名或FQDNs的列表,以扫描证书。
p,ports没有443没有一个或多个有效的、用逗号隔开的TCP端口逗号分隔的TCP端口列表,用于检查证书。如果不指定,该列表默认为仅有443。
spsr,show-port-scan-results没有false没有true,false切换列出主机端口扫描结果。
scp,show-closed-ports没有falsetrue,false切换列出所有主机端口扫描结果,即使是没有任何指定端口处于开放状态的主机。
shwvc,show-hosts-with-valid-certsfalsetrue,false切换为在概览输出中列出所有证书检查结果,即使是有有效证书的主机。
svc,show-valid-certs没有falsetrue,false切换在输出概要中列出所有证书,即使是已经通过所有有效性检查的证书。
so,show-overview没有false没有true,false将摘要输出视图从详细视图切换到概览。

配置文件

目前不支持。如果有
足够的兴趣
,这个功能可能会在以后添加。

例子

check_cert Nagios插件

确定结果

这个例子显示了使用Nagios插件来手动检查
www.google.com 上的
一个远程
认证端口。我们
用一些任意的数字
覆盖了默认的WARNING
CRITICAL 年龄阈值。

注意:使用--verbose 标志来显示进一步的细节。

$ ./check_cert --server www.google.com --port 443 --age-critical 30 --age-warning 50
OK: leaf cert "www.google.com" expires next with 52d 16h remaining (until 2021-09-20 04:12:57 +0000 UTC) [EXPIRED: 0, EXPIRING: 0, OK: 3]

**ERRORS**

* None

**THRESHOLDS**

* CRITICAL: Expires before 2021-08-28 11:55:42 +0000 UTC (30 days)
* WARNING: Expires before 2021-09-17 11:55:42 +0000 UTC (50 days)

**DETAILED INFO**

Certificate 1 of 3 (leaf):
        Name: CN=www.google.com
        SANs entries: [www.google.com]
        Issuer: CN=GTS CA 1C3,O=Google Trust Services LLC,C=US
        Serial: 12:D4:D6:BA:D3:7B:1D:D1:0A:00:00:00:00:EB:61:08
        Issued On: 2021-06-28 04:12:58 +0000 UTC
        Expiration: 2021-09-20 04:12:57 +0000 UTC
        Status: [OK] 52d 16h remaining

Certificate 2 of 3 (intermediate):
        Name: CN=GTS CA 1C3,O=Google Trust Services LLC,C=US
        SANs entries: []
        Issuer: CN=GTS Root R1,O=Google Trust Services LLC,C=US
        Serial: 02:03:BC:53:59:6B:34:C7:18:F5:01:50:66
        Issued On: 2020-08-13 00:00:42 +0000 UTC
        Expiration: 2027-09-30 00:00:42 +0000 UTC
        Status: [OK] 2253d 12h remaining

Certificate 3 of 3 (intermediate):
        Name: CN=GTS Root R1,O=Google Trust Services LLC,C=US
        SANs entries: []
        Issuer: CN=GlobalSign Root CA,OU=Root CA,O=GlobalSign nv-sa,C=BE
        Serial: 77:BD:0D:6C:DB:36:F9:1A:EA:21:0F:C4:F0:58:D3:0D
        Issued On: 2020-06-19 00:00:42 +0000 UTC
        Expiration: 2028-01-28 00:00:42 +0000 UTC
        Status: [OK] 2373d 12h remaining

参见WARNING 示例输出以了解更多细节。

警告结果

这里我们再次做同样的事情,但使用
前面
返回的到期日期值
作为起点,我们故意移动阈值,
以便

触发叶子证书的WARNING 状态:如果叶子
证书的有效期为52天又16小时,我们表示
一旦证书的有效期少于53天,就应该触发
警告

注意:使用--verbose 标志来暴露进一步的细节。

$ ./check_c./check_cert --server www.google.com --port 443 --age-critical 30 --age-warning 53
{"level":"error","version":"check-cert v0.4.2-6-g934c303 (https://github.com/atc0005/check-cert)","logging_level":"info","app_type":"plugin","cert_check_timeout":"10s","age_warning":53,"age_critical":30,"expected_sans_entries":"","server":"www.google.com","port":443,"error":"1 certificates expired or expiring","expired_certs":0,"expiring_certs":1,"time":"2021-07-29T06:57:11-05:00","caller":"github.com/atc0005/check-cert/cmd/check_cert/main.go:241","message":"expired or expiring certs present in chain"}
WARNING: leaf cert "www.google.com" expires next with 52d 16h remaining (until 2021-09-20 04:12:57 +0000 UTC) [EXPIRED: 0, EXPIRING: 1, OK: 2]

**ERRORS**

* 1 certificates expired or expiring

**THRESHOLDS**

* CRITICAL: Expires before 2021-08-28 11:57:11 +0000 UTC (30 days)
* WARNING: Expires before 2021-09-20 11:57:11 +0000 UTC (53 days)

**DETAILED INFO**

Certificate 1 of 3 (leaf):
        Name: CN=www.google.com
        SANs entries: [www.google.com]
        Issuer: CN=GTS CA 1C3,O=Google Trust Services LLC,C=US
        Serial: 12:D4:D6:BA:D3:7B:1D:D1:0A:00:00:00:00:EB:61:08
        Issued On: 2021-06-28 04:12:58 +0000 UTC
        Expiration: 2021-09-20 04:12:57 +0000 UTC
        Status: [WARNING] 52d 16h remaining

Certificate 2 of 3 (intermediate):
        Name: CN=GTS CA 1C3,O=Google Trust Services LLC,C=US
        SANs entries: []
        Issuer: CN=GTS Root R1,O=Google Trust Services LLC,C=US
        Serial: 02:03:BC:53:59:6B:34:C7:18:F5:01:50:66
        Issued On: 2020-08-13 00:00:42 +0000 UTC
        Expiration: 2027-09-30 00:00:42 +0000 UTC
        Status: [OK] 2253d 12h remaining

Certificate 3 of 3 (intermediate):
        Name: CN=GTS Root R1,O=Google Trust Services LLC,C=US
        SANs entries: []
        Issuer: CN=GlobalSign Root CA,OU=Root CA,O=GlobalSign nv-sa,C=BE
        Serial: 77:BD:0D:6C:DB:36:F9:1A:EA:21:0F:C4:F0:58:D3:0D
        Issued On: 2020-06-19 00:00:42 +0000 UTC
        Expiration: 2028-01-28 00:00:42 +0000 UTC
        Status: [OK] 2373d 12h remaining

一些需要注意的事项(按出现顺序排列)。

  1. 提供结构化日志信息的JSON输出

    • 这被发送到stderr
    • Nagios会忽略来自插件的stderr 输出;stdout 是给Nagios的,
      stderr
      是给人类的。
  2. 第二行的单行状态输出

    • Nagios用它来显示
      一个主机的
      所有服务
      检查的
      概况。
    • 这是Nagios用于文本、电子邮件和其他的通知
      (如果配置了
      )。
  3. ERRORS 部分简要说明了证书的问题所在。

  4. CERTIFICATE AGE THRESHOLDS 部分记录了用于
    确定当前服务检查状态(结果)
    的(计算)阈值。

  5. DETAILED INFO 部分包含证书链的概述

    • Nagios用这个来显示详细的服务检查专用
      页面(例如,显示最后一次检查时间、频率、当前状态等

    • 至于单行输出,它被Nagios用于文本、电子邮件和
      其他可能配置的通知

  6. 叶子证书的Status 字段从OK 变成了WARNING
    ,这个插件设置了适当的退出代码,让Nagios知道了这个
    状态变化。

重要的结果

过期的证书

WARNING 的例子一样,我们使用
初始检查
返回的到期日期值
作为起点,故意移动阈值,
以便

触发叶子证书的CRITICAL 状态:如果
叶子证书的有效期为 52 天 16 小时以上,我们为

WARNING
阈值指定 90 天
,为CRITICAL 阈值
指定
60 天。这将
触发一个CRITICAL 状态。

注意:使用--verbose 标志来暴露进一步的细节。

$ ./check_c./check_cert --server www.google.com --port 443 --age-critical 60 --age-warning 90
{"level":"error","version":"check-cert v0.4.2-6-g934c303 (https://github.com/atc0005/check-cert)","logging_level":"info","app_type":"plugin","cert_check_timeout":"10s","age_warning":90,"age_critical":60,"expected_sans_entries":"","server":"www.google.com","port":443,"error":"1 certificates expired or expiring","expired_certs":0,"expiring_certs":1,"time":"2021-07-29T06:58:35-05:00","caller":"github.com/atc0005/check-cert/cmd/check_cert/main.go:241","message":"expired or expiring certs present in chain"}
CRITICAL: leaf cert "www.google.com" expires next with 52d 16h remaining (until 2021-09-20 04:12:57 +0000 UTC) [EXPIRED: 0, EXPIRING: 1, OK: 2]

**ERRORS**

* 1 certificates expired or expiring

**THRESHOLDS**

* CRITICAL: Expires before 2021-09-27 11:58:35 +0000 UTC (60 days)
* WARNING: Expires before 2021-10-27 11:58:35 +0000 UTC (90 days)

**DETAILED INFO**

Certificate 1 of 3 (leaf):
        Name: CN=www.google.com
        SANs entries: [www.google.com]
        Issuer: CN=GTS CA 1C3,O=Google Trust Services LLC,C=US
        Serial: 12:D4:D6:BA:D3:7B:1D:D1:0A:00:00:00:00:EB:61:08
        Issued On: 2021-06-28 04:12:58 +0000 UTC
        Expiration: 2021-09-20 04:12:57 +0000 UTC
        Status: [CRITICAL] 52d 16h remaining

Certificate 2 of 3 (intermediate):
        Name: CN=GTS CA 1C3,O=Google Trust Services LLC,C=US
        SANs entries: []
        Issuer: CN=GTS Root R1,O=Google Trust Services LLC,C=US
        Serial: 02:03:BC:53:59:6B:34:C7:18:F5:01:50:66
        Issued On: 2020-08-13 00:00:42 +0000 UTC
        Expiration: 2027-09-30 00:00:42 +0000 UTC
        Status: [OK] 2253d 12h remaining

Certificate 3 of 3 (intermediate):
        Name: CN=GTS Root R1,O=Google Trust Services LLC,C=US
        SANs entries: []
        Issuer: CN=GlobalSign Root CA,OU=Root CA,O=GlobalSign nv-sa,C=BE
        Serial: 77:BD:0D:6C:DB:36:F9:1A:EA:21:0F:C4:F0:58:D3:0D
        Issued On: 2020-06-19 00:00:42 +0000 UTC
        Expiration: 2028-01-28 00:00:42 +0000 UTC
        Status: [OK] 2373d 12h remaining
过期证书

这里我们使用expired.badssl.com子域来演示
在一个链中遇到一个或多个(这里是多个)过期证书
的结果

除了FQDN之外,所有默认选项(包括端口)都被使用。

注意:使用--verbose 标志来暴露进一步的细节。

$ ./check_cert --server expired.badssl.com
{"level":"error","version":"check-cert v0.4.2-6-g934c303 (https://github.com/atc0005/check-cert)","logging_level":"info","app_type":"plugin","cert_check_timeout":"10s","age_warning":30,"age_critical":15,"expected_sans_entries":"","server":"expired.badssl.com","port":443,"error":"2 certificates expired or expiring","expired_certs":2,"expiring_certs":0,"time":"2021-07-29T07:02:17-05:00","caller":"github.com/atc0005/check-cert/cmd/check_cert/main.go:241","message":"expired or expiring certs present in chain"}
CRITICAL: leaf cert "*.badssl.com" expired 2299d 12h ago (on 2015-04-12 23:59:59 +0000 UTC) [EXPIRED: 2, EXPIRING: 0, OK: 1]

**ERRORS**

* 2 certificates expired or expiring

**THRESHOLDS**

* CRITICAL: Expires before 2021-08-13 12:02:16 +0000 UTC (15 days)
* WARNING: Expires before 2021-08-28 12:02:16 +0000 UTC (30 days)

**DETAILED INFO**

Certificate 1 of 3 (leaf):
        Name: CN=*.badssl.com,OU=Domain Control Validated+OU=PositiveSSL Wildcard
        SANs entries: [*.badssl.com badssl.com]
        Issuer: CN=COMODO RSA Domain Validation Secure Server CA,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB
        Serial: 4A:E7:95:49:FA:9A:BE:3F:10:0F:17:A4:78:E1:69:09
        Issued On: 2015-04-09 00:00:00 +0000 UTC
        Expiration: 2015-04-12 23:59:59 +0000 UTC
        Status: [EXPIRED] 2299d 12h ago

Certificate 2 of 3 (intermediate):
        Name: CN=COMODO RSA Domain Validation Secure Server CA,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB
        SANs entries: []
        Issuer: CN=COMODO RSA Certification Authority,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB
        Serial: 2B:2E:6E:EA:D9:75:36:6C:14:8A:6E:DB:A3:7C:8C:07
        Issued On: 2014-02-12 00:00:00 +0000 UTC
        Expiration: 2029-02-11 23:59:59 +0000 UTC
        Status: [OK] 2754d 11h remaining

Certificate 3 of 3 (intermediate):
        Name: CN=COMODO RSA Certification Authority,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB
        SANs entries: []
        Issuer: CN=AddTrust External CA Root,OU=AddTrust External TTP Network,O=AddTrust AB,C=SE
        Serial: 27:66:EE:56:EB:49:F3:8E:AB:D7:70:A2:FC:84:DE:22
        Issued On: 2000-05-30 10:48:38 +0000 UTC
        Expiration: 2020-05-30 10:48:38 +0000 UTC
        Status: [EXPIRED] 425d 1h ago

lscert CLI工具

确定结果

这个例子显示了使用CLI应用程序来执行与我们
之前使用Nagios插件进行的
相同的初始检查

注意:使用--verbose 标志来揭示进一步的细节。

$ ./lscert --server www.google.com --port 443 --age-critical 50 --age-warning 55

Connecting to remote server "www.google.com" at port 443


=============================
CERTIFICATES | AGE THRESHOLDS
=============================

- WARNING:      Expires before 2020-08-30 11:12:01 +0000 UTC (55 days)
- CRITICAL:     Expires before 2020-08-25 11:12:01 +0000 UTC (50 days)


======================
CERTIFICATES | SUMMARY
======================

- OK: 2 certs found for service running on www.google.com at port 443
- OK: Provided hostname matches discovered certificate
- OK: leaf cert "www.google.com" expires next with 65d 3h remaining (until 2020-09-09 14:31:22 +0000 UTC)
- OK: [EXPIRED: 0, EXPIRING: 0, OK: 2]


============================
CERTIFICATES | CHAIN DETAILS
============================

Certificate 1 of 2 (leaf):
        Name: CN=www.google.com,O=Google LLC,L=Mountain View,ST=California,C=US
        SANs entries: [www.google.com]
        Issuer: CN=GTS CA 1O1,O=Google Trust Services,C=US
        Serial: FD:6F:3E:24:98:C2:5B:1D:08:00:00:00:00:47:F0:33
        Expiration: 2020-09-09 14:31:22 +0000 UTC
        Status: [OK] 65d 3h remaining

Certificate 2 of 2 (intermediate):
        Name: CN=GTS CA 1O1,O=Google Trust Services,C=US
        SANs entries: []
        Issuer: CN=GlobalSign,OU=GlobalSign Root CA - R2,O=GlobalSign
        Serial: 01:E3:B4:9A:A1:8D:8A:A9:81:25:69:50:B8
        Expiration: 2021-12-15 00:00:42 +0000 UTC
        Status: [OK] 526d 12h remaining

警告的结果

注意:使用--verbose 标志来揭示进一步的细节。

$ ./lscert --server www.google.com --port 443 --age-critical 50 --age-warning 66

Connecting to remote server "www.google.com" at port 443


=============================
CERTIFICATES | AGE THRESHOLDS
=============================

- WARNING:      Expires before 2020-09-10 11:13:11 +0000 UTC (66 days)
- CRITICAL:     Expires before 2020-08-25 11:13:11 +0000 UTC (50 days)


======================
CERTIFICATES | SUMMARY
======================

- OK: 2 certs found for service running on www.google.com at port 443
- OK: Provided hostname matches discovered certificate
- WARNING: leaf cert "www.google.com" expires next with 65d 3h remaining (until 2020-09-09 14:31:22 +0000 UTC)
- WARNING: [EXPIRED: 0, EXPIRING: 1, OK: 1]


============================
CERTIFICATES | CHAIN DETAILS
============================

Certificate 1 of 2 (leaf):
        Name: CN=www.google.com,O=Google LLC,L=Mountain View,ST=California,C=US
        SANs entries: [www.google.com]
        Issuer: CN=GTS CA 1O1,O=Google Trust Services,C=US
        Serial: FD:6F:3E:24:98:C2:5B:1D:08:00:00:00:00:47:F0:33
        Expiration: 2020-09-09 14:31:22 +0000 UTC
        Status: [WARNING] 65d 3h remaining

Certificate 2 of 2 (intermediate):
        Name: CN=GTS CA 1O1,O=Google Trust Services,C=US
        SANs entries: []
        Issuer: CN=GlobalSign,OU=GlobalSign Root CA - R2,O=GlobalSign
        Serial: 01:E3:B4:9A:A1:8D:8A:A9:81:25:69:50:B8
        Expiration: 2021-12-15 00:00:42 +0000 UTC
        Status: [OK] 526d 12h remaining

一般来说,这两个
工具
OKWARNING 输出之间的差异
很小。然而,与check_cert Nagios插件不同的是,我们被
限制在一行摘要输出,lscert CLI工具没有
相同的输出要求,可以有更多的表现力(例如,如摘要
部分,以突出特定的兴趣项目)。与check_cert

Nagios插件一样
lscert CLI工具也显示用于
确定应用于证书链的检查状态


阈值

重要的结果

这里我们使用expired.badssl.com子域来演示
在一个链中遇到一个或多个(在本例中是多个)过期证书
的结果

除了FQDN外,所有默认选项(包括端口)都被使用。

注意:使用--verbose 标志来显示进一步的细节。

$ ./lscert --server expired.badssl.com

Connecting to remote server "expired.badssl.com" at port 443


=============================
CERTIFICATES | AGE THRESHOLDS
=============================

- WARNING:      Expires before 2020-08-05 11:14:32 +0000 UTC (30 days)
- CRITICAL:     Expires before 2020-07-21 11:14:32 +0000 UTC (15 days)


======================
CERTIFICATES | SUMMARY
======================

- OK: 3 certs found for service running on expired.badssl.com at port 443
- OK: Provided hostname matches discovered certificate
- CRITICAL: leaf cert "*.badssl.com" expired 1911d 11h ago (on 2015-04-12 23:59:59 +0000 UTC)
- CRITICAL: [EXPIRED: 2, EXPIRING: 0, OK: 1]


============================
CERTIFICATES | CHAIN DETAILS
============================

Certificate 1 of 3 (leaf):
        Name: CN=*.badssl.com,OU=Domain Control Validated+OU=PositiveSSL Wildcard
        SANs entries: [*.badssl.com badssl.com]
        Issuer: CN=COMODO RSA Domain Validation Secure Server CA,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB
        Serial: 4A:E7:95:49:FA:9A:BE:3F:10:0F:17:A4:78:E1:69:09
        Expiration: 2015-04-12 23:59:59 +0000 UTC
        Status: [EXPIRED] 1911d 11h ago

Certificate 2 of 3 (intermediate):
        Name: CN=COMODO RSA Domain Validation Secure Server CA,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB
        SANs entries: []
        Issuer: CN=COMODO RSA Certification Authority,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB
        Serial: 2B:2E:6E:EA:D9:75:36:6C:14:8A:6E:DB:A3:7C:8C:07
        Expiration: 2029-02-11 23:59:59 +0000 UTC
        Status: [OK] 3142d 12h remaining

Certificate 3 of 3 (intermediate):
        Name: CN=COMODO RSA Certification Authority,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB
        SANs entries: []
        Issuer: CN=AddTrust External CA Root,OU=AddTrust External TTP Network,O=AddTrust AB,C=SE
        Serial: 27:66:EE:56:EB:49:F3:8E:AB:D7:70:A2:FC:84:DE:22
        Expiration: 2020-05-30 10:48:38 +0000 UTC
        Status: [EXPIRED] 37d 0h ago

CERTIFICATES | SUMMARY 部分中的一些项目需要注意。

  • 列出了首先过期的证书(叶子证书*.badssl.com )。

    • 链的位置
    • 过期概要
    • 过期日期
  • 快速统计EXPIRED,EXPIRINGOK 的证书。

  • 未来的工作可能会列出所有过期的证书,但假设
    列出第一个过期的证书,然后
    在下一节

    列出链的

    细节(明确指出过期
    状态)就足够了

fixsn CLI工具

无效输入

$ ./fixsn badinput
Error: Invalid serial number (in base 10 format)
Example expected input: 336872288293767042001244177974291853363

预期的输入

$ ./fixsn 336872288293767042001244177974291853363
FD:6F:3E:24:98:C2:5B:1D:08:00:00:00:00:47:F0:33

certsum CLI工具

该工具处于早期开发阶段,
在未来的版本中,
可用的选项可能会发生变化
(甚至可能是重大变化)。

请参阅本
README
前面记录的可用标志/选项的列表
,以了解更多选项。

证书概述

以下选项为每台
有证书的
主机生成一个单行的高级概述
。没有证书的主机将从结果中省略。

$ ./certsum --hosts 192.168.5.0/24 --show-hosts-with-valid-certs --show-overview
Beginning cert scan against 254 unique hosts using ports: [443]
...................
Completed certificates scan in 2.3670248s
19 certificates (8 issues) found.

Results (all):

IP Address            Port    Subject or SANs                       Status          Chain Summary                           Serial
---                   ---     ---                                   ---             ---                                     ---
192.168.5.22          443     VMware                                ⛔ (!!)         [EXPIRED: 1, EXPIRING: 0, OK: 0]        92:4A:AD:38:3C:DC:C1:B6
192.168.5.3           443     VMware                                ⛔ (!!)         [EXPIRED: 1, EXPIRING: 0, OK: 0]        DE:FD:50:2B:C5:7F:79:F4
192.168.5.24          443     VMware                                ✅ (OK)         [EXPIRED: 0, EXPIRING: 0, OK: 1]        9A:DF:A1:A6:60:16:4E:C0
192.168.5.11          443     VMware                                ⛔ (!!)         [EXPIRED: 1, EXPIRING: 0, OK: 0]        8D:2C:61:CF:AE:57:58:98
192.168.5.83          443     HP Jetdirect 4639304E                 ⛔ (!!)         [EXPIRED: 1, EXPIRING: 0, OK: 0]        47:F0:56:50
192.168.5.109         443     HP LaserJet M506 F2A68A               ⛔ (!!)         [EXPIRED: 1, EXPIRING: 0, OK: 0]        -29:25:F5:A8:D5:E2:FC:C3:71:77:F4:48:3A:09:2E:24:0F:0E:37:1A
192.168.5.93          443     NPI25BC25                             ✅ (OK)         [EXPIRED: 0, EXPIRING: 0, OK: 1]        -61:CE:BD:13
192.168.5.113         443     NPI253CDE                             ✅ (OK)         [EXPIRED: 0, EXPIRING: 0, OK: 1]        38:BC:BD:21
192.168.5.136         443     HP Jetdirect BAC74492                 ✅ (OK)         [EXPIRED: 0, EXPIRING: 0, OK: 1]        20:46:94:C0
192.168.5.104         443     HP Jetdirect 7FE7AF22                 ⛔ (!!)         [EXPIRED: 1, EXPIRING: 0, OK: 0]        02
192.168.5.165         443     192.168.5.165                         ⛔ (!!)         [EXPIRED: 1, EXPIRING: 0, OK: 0]        EF:E5:A3:0E:2F:FA:C1:3A
192.168.5.183         443     192.168.5.183                         ⛔ (!!)         [EXPIRED: 1, EXPIRING: 0, OK: 0]        F7:A2:CD:4A:F2:A0:63:10
192.168.5.182         443     192.168.5.182                         ✅ (OK)         [EXPIRED: 0, EXPIRING: 0, OK: 1]        AC:53:68:BB:38:5E:5A:6C
192.168.5.105         443     192.168.5.105                         ✅ (OK)         [EXPIRED: 0, EXPIRING: 0, OK: 1]        64:36:33:33:32:36:37:38:30:31:64:66:37:31:31:62:32:62:37:63

值得注意的是。

  • 隐含地使用默认端口为443/tcp
  • 扫描整个192.168.5.0/24 范围
  • 概览或摘要格式生成输出
  • 显示 "OK "的主机和有问题的主机(为简洁起见通常省略)。

CIDR范围

$ ./certsum --ports 443 --hosts 192.168.5.0/24
Total IPs from all ranges before deduping: 254
Total IPs from all ranges after deduping: 254
Beginning scan of ports: [443]
Completed port scan
Beginning certificate analysis
..........................
Completed certificate analysis

Results:

IP Address              Port    Subject or SANs                 Status (Type)                   Summary                         Serial
---                     ---     ---                             ---                             ---                             ---
192.168.5.104           443     HP Jetdirect 7FE7AF22           ⛔ (leaf; self-signed)          [EXPIRED] 3942d 12h ago         02
192.168.5.3             443     VMware                          ⛔ (root)                       [EXPIRED] 571d 23h ago          DE:FD:50:2B:C5:7F:79:F4
192.168.5.109           443     HP LaserJet M506 F2A68A         ⛔ (leaf; self-signed)          [CRITICAL] 1d 7h remaining      -29:25:F5:A8:D5:E2:FC:C3:71:77:F4:48:3A:09:2E:24:0F:0E:37:1A
192.168.5.83            443     HP Jetdirect 4639304E           ⛔ (leaf; self-signed)          [EXPIRED] 2175d 12h ago         47:F0:56:50
192.168.5.165           443     192.168.5.165                   ⛔ (leaf; self-signed)          [EXPIRED] 1519d 7h ago          EF:E5:A3:0E:2F:FA:C1:3A
192.168.5.183           443     192.168.5.183                   ⛔ (leaf; self-signed)          [EXPIRED] 1034d 19h ago         F7:A2:CD:4A:F2:A0:63:10

值得注意的是

  • 明确指定端口443/tcp (默认)。
  • 扫描整个192.168.5.0/24 范围
  • 只发出 "问题 "条目

部分范围

这里我们指定一个部分范围,使用的语法有意类似于
nmap(一个
了不起的工具)
所接受的基于八位数的寻址语法

目前

支持
八位数内的逗号(为了排除IP)

$ ./certsum --ports 443 --hosts 192.168.5.104-110
Total IPs from all ranges before deduping: 6
Total IPs from all ranges after deduping: 6
Beginning scan of ports: [443]
Completed port scan
Beginning certificate analysis
..........................
Completed certificate analysis

Results:

IP Address              Port    Subject or SANs                 Status (Type)                   Summary                         Serial
---                     ---     ---                             ---                             ---                             ---
192.168.5.104           443     HP Jetdirect 7FE7AF22           ⛔ (leaf; self-signed)          [EXPIRED] 3942d 12h ago         02
192.168.5.109           443     HP LaserJet M506 F2A68A         ⛔ (leaf; self-signed)          [CRITICAL] 1d 7h remaining      -29:25:F5:A8:D5:E2:FC:C3:71:77:F4:48:3A:09:2E:24:0F:0E:37:1A

部分范围和单一IP地址

$ ./certsum --ports 443 --hosts 192.168.5.3,192.168.5.104-110
Total IPs from all ranges before deduping: 7
Total IPs from all ranges after deduping: 7
Beginning scan of ports: [443]
Completed port scan
Beginning certificate analysis
..........................
Completed certificate analysis

Results:

IP Address              Port    Subject or SANs                 Status (Type)                   Summary                         Serial
---                     ---     ---                             ---                             ---                             ---
192.168.5.3             443     VMware                          ⛔ (root)                       [EXPIRED] 577d 0h ago           DE:FD:50:2B:C5:7F:79:F4
192.168.5.104           443     HP Jetdirect 7FE7AF22           ⛔ (leaf; self-signed)          [EXPIRED] 3942d 12h ago         02
192.168.5.109           443     HP LaserJet M506 F2A68A         ⛔ (leaf; self-signed)          [CRITICAL] 1d 7h remaining      -29:25:F5:A8:D5:E2:FC:C3:71:77:F4:48:3A:09:2E:24:0F:0E:37:1A

部分范围、CIDR范围和一个单一的IP地址

$ ./certsum --ports 443 --hosts 192.168.5.3,192.168.5.104-110,192.168.2.0/24
Total IPs from all ranges before deduping: 260
Total IPs from all ranges after deduping: 260
Beginning scan of ports: [443]
Completed port scan
Beginning certificate analysis
...............................................................

由于输出结果与其他
例子
密切相关,因此只包括引言文本。

单个IP地址和一个FQDN

值得注意的是

  • 默认的HTTPS端口(因为我们没有指定一个)。
  • 我们正在使用一个FQDN
$ ./certsum --hosts 192.168.5.3,expired.badssl.com
Total IPs from all ranges before deduping: 2
Total IPs from all ranges after deduping: 2
Beginning scan of ports: [443]
Completed port scan
Beginning certificate analysis
..
Completed certificate analysis

Results:

IP Address              Port    Subject or SANs                                 Status (Type)           Summary                         Serial
---                     ---     ---                                             ---                     ---                             ---
192.168.5.3             443     VMware                                          ⛔ (root)               [EXPIRED] 577d 0h ago           DE:FD:50:2B:C5:7F:79:F4
104.154.89.105          443     badssl-fallback-unknown-subdomain-or-no-sni     ⛔ (leaf)               [EXPIRED] 865d 13h ago          CD:BC:5A:4A:EC:97:67:B1

显示所有的扫描结果

我们包括一个额外的没有证书的扫描目标,以说明
默认扫描结果通常会被静音/隐藏起来。

$ ./certsum --hosts 192.168.5.3,expired.badssl.com,scanme.nmap.org --show-valid-certs --show-port-scan-results --show-hosts-with-valid-certs --show-closed-ports
Total IPs from all ranges before deduping: 4
Total IPs from all ranges after deduping: 4
Beginning scan of ports: [443]
Completed port scan
Beginning certificate analysis
192.168.5.3: [443: true]
104.154.89.105: [443: true]
45.33.32.156: [None]
2600:3c01::f03c:91ff:fe18:bb2f: [None]
Completed certificate analysis

Results:

IP Address              Port    Subject or SANs                                 Status (Type)           Summary                         Serial
---                     ---     ---                                             ---                     ---                             ---
192.168.5.3             443     VMware                                          ⛔ (root)               [EXPIRED] 577d 21h ago          DE:FD:50:2B:C5:7F:79:F4
104.154.89.105          443     badssl-fallback-unknown-subdomain-or-no-sni     ⛔ (leaf)               [EXPIRED] 865d 13h ago          CD:BC:5A:4A:EC:97:67:B1

许可证

MIT License

Copyright (c) 2020 Adam Chalkley

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

GitHub

github.com/atc0005/che…