如果我在Mac或Linux中有实际的文件和Bash shell,我如何查询证书文件何时到期?不是网站,实际上是证书文件本身,假设我有csr、key、pem和chain文件。
当前回答
openssl:
openssl x509 -enddate -noout -in file.pem
输出在表单上:
notAfter=Nov 3 22:23:50 2014 GMT
还可以参阅MikeW的回答,了解如何轻松地检查证书是否过期,或者是否会在某个时间段内过期,而不必解析上面的日期。
其他回答
与接受的答案相同,但请注意,它甚至适用于。crt文件,而不仅仅是。pem文件,以防万一,如果你无法找到。pem文件的位置。
openssl x509 -enddate -noout -in e71c8ea7fa97ad6c.crt
结果:
notAfter=Mar 29 06:15:00 2020 GMT
openssl:
openssl x509 -enddate -noout -in file.pem
输出在表单上:
notAfter=Nov 3 22:23:50 2014 GMT
还可以参阅MikeW的回答,了解如何轻松地检查证书是否过期,或者是否会在某个时间段内过期,而不必解析上面的日期。
如果(出于某种原因)您想在Linux中使用GUI应用程序,请使用gcr-viewer(在大多数发行版中,它是由包gcr安装的(否则在包gcr-viewer中))
gcr-viewer file.pem
# or
gcr-viewer file.crt
如果你只想知道证书是否已经过期(或者将在接下来的N秒内过期),openssl x509的-checkend <seconds>选项将告诉你:
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将返回0(零)的退出码,并且在接下来的86400秒内不会这样做。如果证书已经过期或已经过期——或者出现其他错误,如文件无效/不存在——则返回代码为1。
(当然,它假设时间/日期设置正确)
请注意,旧版本的openssl有一个错误,这意味着如果在checkend中指定的时间太大,将总是返回0 (https://github.com/openssl/openssl/issues/6180)。
变成bash变量
由于这个问题被标记为bash,我经常使用UNIX EPOCH来存储日期,这对于计算$EPOCHSECONDS剩余的时间很有用,并通过printf '%(dateFmt)T bashism格式化输出:
{ read -r certStart;read -r certEnd;}< <(date -f <(cut -d = -f 2 <(
openssl x509 -dates -noout -in "$file")) +%s)
Then
printf '%-6s %(%a %d %b %Y, %H %Z)T\n' 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
...
更完整的bash 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=$'\n';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字段filename: declare -A Subj='([CN]="${file##*/}")'
完整bash脚本
这里共享一个完整的bash脚本,显示所有来自命令行参数的证书,可以通过文件,域名或IPv4地址。将在一行中输出过去的天数,剩余天数,替代域的数量和所有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=$'\n';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\n' Not\ before Not\ after left \
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" \
<<<$'HEAD / HTTP/1.0\r\n\r' 2> /dev/null)
else
echo "Unknown argument: '$arg'."
fi
done
使用示例:
./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