如何从 PEM 编码证书确定 SSL 证书的到期日期?

2024-10-28 08:37:00
admin
原创
71
摘要:问题描述:如果我有实际文件和 Mac 或 Linux 中的 Bash shell,我该如何查询证书文件以了解其何时过期?不是网站,而是证书文件本身,假设我有 csr、key、pem 和 chain 文件。解决方案 1:和openssl:openssl x509 -enddate -noout -in file...

问题描述:

如果我有实际文件和 Mac 或 Linux 中的 Bash shell,我该如何查询证书文件以了解其何时过期?不是网站,而是证书文件本身,假设我有 csr、key、pem 和 chain 文件。


解决方案 1:

openssl

openssl x509 -enddate -noout -in file.pem

输出形式如下:

notAfter=Nov  3 22:23:50 2014 GMT

另请参阅MikeW 的回答,了解如何轻松检查证书是否已过期,或者是否会在一定时间段内过期,而无需解析上述日期。

解决方案 2:

如果您只是想知道证书是否已过期(或者将在接下来的 N 秒内过期),则选项-checkend <seconds>openssl x509告诉您:

if openssl x509 -checkend 86400 -noout -in file.pem
then
  echo "Certificate is good for another day!"
else
  echo "Certificate has expired or will do so within 24 hours!"
  echo "(or is invalid/not found)"
fi

这省去了您自己进行日期/时间比较的麻烦。

openssl如果证书尚未过期,并且在接下来的 86400 秒内不会过期(如上例所示),则将返回退出代码0(零)。如果证书即将过期或已经过期 - 或者出现其他错误(如文件无效/不存在),则返回代码为1

(当然,假设时间/日期设置正确)

请注意,旧版本的 openssl 有一个错误,这意味着如果指定的时间checkend太大,则始终会返回 0(https://github.com/openssl/openssl/issues/6180)。

解决方案 3:

这是我的 bash 命令行,用于按到期顺序列出多个证书,最近到期的证书首先到期。

for pem in /etc/ssl/certs/*.pem; do 
   printf '%s: %s
' \n      "$(date --date="$(openssl x509 -enddate -noout -in "$pem"|cut -d= -f 2)" --iso-8601)" \n      "$pem"
done | sort

示例输出:

2015-12-16: /etc/ssl/certs/Staat_der_Nederlanden_Root_CA.pem
2016-03-22: /etc/ssl/certs/CA_Disig.pem
2016-08-14: /etc/ssl/certs/EBG_Elektronik_Sertifika_Hizmet_S.pem

解决方案 4:

命令:

# cat {key_name} | openssl x509 -noout -enddate
Example: # cat tower.cert | openssl x509 -noout -enddate

结果:

notAfter=Dec  7 04:03:32 2023 GMT

解决方案 5:

与接受的答案相同,但请注意,它甚至可以用于.crt文件而不仅仅是.pem文件,以防您无法找到.pem文件位置。

openssl x509 -enddate -noout -in e71c8ea7fa97ad6c.crt

结果:

notAfter=Mar 29 06:15:00 2020 GMT

解决方案 6:

这是一个 bash 函数,它检查所有服务器,假设您使用 DNS 循环。请注意,这需要 GNU 日期,并且不适用于 Mac OS

function check_certs () {
  if [ -z "$1" ]
  then
    echo "domain name missing"
    exit 1
  fi
  name="$1"
  shift

  now_epoch=$( date +%s )

  dig +noall +answer $name | while read _ _ _ _ ip;
  do
    echo -n "$ip:"
    expiry_date=$( echo | openssl s_client -showcerts -servername $name -connect $ip:443 2>/dev/null | openssl x509 -inform pem -noout -enddate | cut -d "=" -f 2 )
    echo -n " $expiry_date";
    expiry_epoch=$( date -d "$expiry_date" +%s )
    expiry_days="$(( ($expiry_epoch - $now_epoch) / (3600 * 24) ))"
    echo "    $expiry_days days"
  done
}

输出示例:

$ check_certs stackoverflow.com
151.101.1.69: Aug 14 12:00:00 2019 GMT    603 days
151.101.65.69: Aug 14 12:00:00 2019 GMT    603 days
151.101.129.69: Aug 14 12:00:00 2019 GMT    603 days
151.101.193.69: Aug 14 12:00:00 2019 GMT    603 days

解决方案 7:

一行检查域名证书是否在一段时间后过期(例如 15 天):

openssl x509 -checkend $(( 24*3600*15 )) -noout -in <(openssl s_client -showcerts -connect my.domain.com:443 </dev/null 2>/dev/null | openssl x509 -outform PEM)
if [ $? -eq 0 ]; then
  echo 'good'
else
  echo 'bad'
fi

解决方案 8:

openssl将字段存储到狂欢变量

由于这个问题被标记为狂欢,我经常用它来存储日期,这对于计算剩余时间和通过bashism格式化输出UNIX EPOCH很有用:$EPOCHSECONDS`printf '%(dateFmt)T`

{ read -r certStart;read -r certEnd;}< <(date -f <(cut -d = -f 2 <(
    openssl x509 -dates -noout -in "$file")) +%s)

然后

printf '%-6s %(%a %d %b %Y, %H %Z)T
' start $certStart end $certEnd
start  Mon 01 Nov 2004, 17 UTC
end    Mon 01 Jan 2035, 05 UTC

示例,列出内容/etc/ssl/certs并计算剩余天数:

for file in /etc/ssl/certs/*pem;do
    { read -r certStart;read -r certEnd;}< <(
        date -f <(cut -d = -f 2 <(
            openssl x509 -dates -noout -in "$file")) +%s)
    printf "%(%d %b %Y %T)T - %(%d %b %Y %T)T: %6d %s
" \n        $certStart $certEnd $(( (certEnd - EPOCHSECONDS)/86400 )) ${file##*/}
done
05 May 2011 09:37:37 - 31 Dec 2030 09:37:37:   3034 ACCVRAIZ1.pem
26 Oct 2010 08:38:03 - 26 Oct 2040 08:38:03:   6620 Buypass_Class_2_Root_CA.pem
19 Jan 2010 00:00:00 - 18 Jan 2038 23:59:59:   5609 COMODO_RSA_Certification_Authority.pem
13 Nov 2012 00:00:00 - 19 Jan 2038 03:14:07:   5609 GlobalSign_ECC_Root_CA_-_R4.pem
06 Apr 2001 07:29:40 - 06 Apr 2021 07:29:40:   -522 Sonera_Class_2_Root_CA.pem
29 Jun 2004 17:39:16 - 29 Jun 2034 17:39:16:   4310 Starfield_Class_2_CA.pem
04 Feb 2016 12:32:16 - 31 Dec 2029 17:23:16:   2669 TrustCor_RootCert_CA-1.pem
01 Nov 2004 17:14:04 - 01 Jan 2035 05:37:19:   4495 XRamp_Global_CA_Root.pem
...

更加完整狂欢x509 读数:

for file in /etc/ssl/certs/*pem;do
    mapfile -t x509 < <(openssl x509 -noout -dates -subject -in "$file")
    x509=("${x509[@]#*=}")
    mapfile -t dates < <(IFS=$'
';date -f - <<<"${x509[*]::2}" +%s) 
    str="${x509[-1]}"
    declare -A Subj='([CN]="${file##*/}")'
    while [[ "$str" ]] ;do
        lhs=${str%%=*} rhs=${str#$lhs= } rhs=${rhs%% = *} rhs=${rhs%, *}
        Subj[${lhs// }]="$rhs"
        str=${str#"$lhs= $rhs"} str=${str#, }
    done
    printf "%(%d %b %Y %T)T - %(%d %b %Y %T)T: %s
" \n        ${dates[@]} "${Subj[CN]}"
done
05 May 2011 09:37:37 - 31 Dec 2030 09:37:37:   3034 ACCVRAIZ1
26 Oct 2010 08:38:03 - 26 Oct 2040 08:38:03:   6620 Buypass Class 2 Root CA
19 Jan 2010 00:00:00 - 18 Jan 2038 23:59:59:   5609 COMODO RSA Certification Authority
13 Nov 2012 00:00:00 - 19 Jan 2038 03:14:07:   5609 GlobalSign
06 Apr 2001 07:29:40 - 06 Apr 2021 07:29:40:   -522 Sonera Class2 CA
29 Jun 2004 17:39:16 - 29 Jun 2034 17:39:16:   4310 Starfield_Class_2_CA.pem
04 Feb 2016 12:32:16 - 31 Dec 2029 17:23:16:   2669 TrustCor RootCert CA-1
01 Nov 2004 17:14:04 - 01 Jan 2035 05:37:19:   4495 XRamp Global Certification Authority
...

注意:有些证书在主题中没有CN字段。为此,我$Subj通过将字段设置为文件名来初始化数组CN
declare -A Subj='([CN]="${file##*/}")'

满的狂欢脚本

这里分享一个完整的 bash 脚本,显示来自命令行参数的所有证书,可以通过filedomain name或 来显示IPv4 address。将在一行(长行)中输出过去几天剩余天数替代域的数量和所有alt :

#!/bin/bash

showCert() {
    local x509 dates lhs rhs str alts
    mapfile -t x509 < <(
        openssl x509 -noout -dates -subject -ext subjectAltName -in "$1")
    x509=("${x509[@]#*=}")
    mapfile -t dates < <(IFS=$'
';date -f - <<<"${x509[*]::2}" +%s)
    str="${x509[2]}"
    local -A Subj;Subj[CN]="${file##*/}"
    while [[ -n "$str" ]]; do
        lhs=${str%%=*} rhs=${str#$lhs= } rhs=${rhs%% = *} rhs=${rhs%, *}
        Subj[${lhs// }]="$rhs"
        str=${str#"$lhs= $rhs"} str=${str#, }
    done
    read -ra alts <<<"${x509[4]//,}"
    alts=("${alts[@]#*:}")
    printf "  %(%d %b %Y %H:%M)T %(%d %b %Y %H:%M)T %6d %6d %-30s %3d %s
" \n        "${dates[@]}" $(((dates[1]-EPOCHSECONDS)/86400)) $(((EPOCHSECONDS-
          dates[0])/86400)) "${Subj[CN]}" "${#alts[@]}" "${alts[*]}" 
}
checkIsIpv4() { # throw an error if not valid IPv4
    local _iPointer _i _a _vareq=()
    for _i ;do
        case $_i in *[^0-9.]* ) return 1 ;; esac
        read -ra _a <<<"${_i//./ }"
        [ ${#_a[@]} -eq 4 ] || return 1
        for _iPointer in "${_a[@]}" ;do
            (( _iPointer == ( _iPointer & 255 ) ))  || return 2
        done
    done
}
checkIsLabel() {
    ((${#1}<4 || ${#1}>253)) && return 1
    [[ -z ${1//[a-zA-Z0-9.-]} ]] || return 2
    [[ -z ${1//.} ]] && return 3
    set -- ${1//./ }
    (($#<2 )) && return 4
    :
}
printf '  %-17s %-17s %6s %6s %-30s %2s
' Not before Not after left \n       past Common Name Alt 

for arg ;do
    if [ -f "$arg" ] ;then
        showCert "$arg"
    elif checkIsLabel "$arg" || checkIsIpv4 "$arg" ;then
        showCert <(openssl s_client -ign_eof -connect "$arg:443" \n                           <<<$'HEAD / HTTP/1.0

' 2> /dev/null)
    else
        echo "Unknown argument: '$arg'."
    fi
done

解释

  • 函数showCert创建一个包含日期主题替代名称的数组变量 $x590

  • 使用mapfile和(仅1个分支)date转换开始 日期 结束日期

  • 创建一个关联数组变量 $Subj来解析主题字符串(第三行${x509[2]}:)

  • 将备选 名称拆分到 另一个数组中:$alts .

  • 使用printf格式化和打印每个证书显示

    • 开始日期

    • 结束日期

    • 剩余天数

    • 过去的日子里

    • 通用名称

    • 替代名称的数量

    • 替代名称

使用示例:

./certShow.sh /etc/ssl/certs/ssl-cert-snakeoil.pem www.example.com
  Not before        Not after           left   past Common Name                    Alt
  08 Sep 2021 16:49 06 Sep 2031 16:49   3277    372 hostname.local                   1 hostname.local
  14 Mar 2022 00:00 14 Mar 2023 23:59    179    186 www.example.org                  8 www.example.org example.net example.edu example.com example.org www.example.com www.example.edu www.example.net

解决方案 9:

对于 MAC OSX (El Capitan),Nicholas 示例的这个修改对我有用。

for pem in /path/to/certs/*.pem; do
    printf '%s: %s
' \n        "$(date -jf "%b %e %H:%M:%S %Y %Z" "$(openssl x509 -enddate -noout -in "$pem"|cut -d= -f 2)" +"%Y-%m-%d")" \n    "$pem";
done | sort

示例输出:

2014-12-19: /path/to/certs/MDM_Certificate.pem
2015-11-13: /path/to/certs/MDM_AirWatch_Certificate.pem

macOS 不喜欢我的系统上的--date=--iso-8601标志。

解决方案 10:

如果(出于某种原因)您想在 Linux 中使用 GUI 应用程序,请使用gcr-viewer(在大多数发行版中,它由包安装gcr(否则在包中gcr-viewer))

gcr-viewer file.pem
# or
gcr-viewer file.crt

解决方案 11:

这是用于跟踪您的 Letsencrypt 或其他证书的更新的 bash 脚本。结果已排序,方便查看。

#!/bin/sh
echo "Certs expiration"
for filename in /etc/letsencrypt/live/*/cert.pem; do
    cert=$(openssl x509 -enddate -subject -noout -in "$filename")
    date=$(echo "$cert" | awk 'FNR == 1' | cut -c10- | date +%s -f -)
    dexp=$(echo "$cert" | awk 'FNR == 1' | cut -c10-)
    subj=$(echo "$cert" | awk 'FNR == 2' | cut -c14-)
    echo "$date $dexp $subj"
done | sort -n -k1 | cut -d' ' -f2- | awk '{print "- "$0}'

您可以调整存储证书的路径。

输出示例:

Certs expiration
- Sep 30 03:30:14 2024 GMT example1.com
- Sep 30 03:31:19 2024 GMT example1.org
- Oct  7 03:31:04 2024 GMT example2.com
- Oct  7 03:40:39 2024 GMT example2.org
- Oct  7 07:35:30 2024 GMT example3.com

享受!

解决方案 12:

我制作了一个与之相关的 bash 脚本来检查证书是否已过期。如果需要,您可以使用它。

脚本

https://github.com/zeeshanjamal16/usefulScripts/blob/master/sslCertificateExpireCheck.sh

自述

https://github.com/zeeshanjamal16/usefulScripts/blob/master/README.md

解决方案 13:

使用openssl

这是一个打印出人类可读文本的脚本cert-etime-check.sh

#!/bin/bash

set -euo pipefail

### get a cert file
declare -r cert_file=${1:? error ... cert_file ?}

### start and end dates
declare -r beg_date=$(openssl x509 -noout -startdate -in $cert_file)
declare -r end_date=$(openssl x509 -noout -enddate -in $cert_file)

### subject and issuer
declare -r subject=$(openssl x509 -noout -subject -in $cert_file)
declare -r issuer=$(openssl x509 -noout -issuer -in $cert_file)

### calculate days gone and left
declare -ir beg_sec=$(date --date="${beg_date##*=}" +%s)
declare -ir end_sec=$(date --date="${end_date##*=}" +%s)
declare -ir now_sec=$(date +%s)

declare -ir day_gone=$(( $((now_sec - beg_sec)) / 86400))
declare -ir day_left=$(( $((end_sec - now_sec)) / 86400))

### print result
date --date="${beg_date##*=}" +"beg: %F-%A (gone: $day_gone)"
date --date="${end_date##*=}" +"end: %F-%A (left: $day_left)"
echo sum: $((day_gone + $day_left))
echo sub: ${subject##* = }
echo iss: ${issuer##* = }
echo
date +"now: %F-%A"

用法:./cert-etime-check.sh cert.pem

输出:

beg: 2024-03-04-Monday (gone: 26)
end: 2024-06-02-Sunday (left: 63)
sum: 89
sub: ******.***
iss: R3

now: 2024-03-31-Sunday
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用