[ini]
This commit is contained in:
commit
6b38521bea
78
source/helpers/certinfo.py
Normal file
78
source/helpers/certinfo.py
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
import subprocess as _subprocess
|
||||
|
||||
|
||||
def get_certificate_info_raw(source):
|
||||
p1 = _subprocess.Popen(
|
||||
["openssl", "x509", "-outform", "pem"],
|
||||
stdin = _subprocess.PIPE,
|
||||
stdout = _subprocess.PIPE
|
||||
)
|
||||
(p1_stdout, p1_stderr, ) = p1.communicate(input = bytes(source, "utf-8"))
|
||||
p2 = _subprocess.Popen(
|
||||
["openssl", "x509", "-noout", "-text"],
|
||||
stdin = _subprocess.PIPE,
|
||||
stdout = _subprocess.PIPE
|
||||
)
|
||||
(p2_stdout, p2_stderr, ) = p2.communicate(input = p1_stdout)
|
||||
return p2_stdout.decode("utf-8")
|
||||
|
||||
|
||||
def get_certificate_info_from_file(path):
|
||||
return get_certificate_info_raw(
|
||||
_subprocess.check_output(
|
||||
["cat", path],
|
||||
text = True
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def get_certificate_info_from_internet(domain):
|
||||
return get_certificate_info_raw(
|
||||
_subprocess.check_output(
|
||||
["openssl", "s_client", "-connect", ("%s:443" % domain), "-showcerts"],
|
||||
stdin = _subprocess.DEVNULL,
|
||||
stderr = _subprocess.DEVNULL,
|
||||
text = True
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def extract_fingerprint(certificate_info):
|
||||
state = {
|
||||
"situation": 0,
|
||||
"result": "",
|
||||
}
|
||||
for line in certificate_info.split("\n"):
|
||||
if (state["situation"] == 0):
|
||||
if (line.strip() == "Subject Public Key Info:"):
|
||||
state = {
|
||||
"situation": 1,
|
||||
"result": state["result"],
|
||||
}
|
||||
else:
|
||||
pass
|
||||
elif (state["situation"] == 1):
|
||||
if (line.strip() == "pub:"):
|
||||
state = {
|
||||
"situation": 2,
|
||||
"result": state["result"],
|
||||
}
|
||||
else:
|
||||
pass
|
||||
elif (state["situation"] == 2):
|
||||
if (line.startswith(" ")):
|
||||
state = {
|
||||
"situation": 2,
|
||||
"result": (state["result"] + line.strip().replace(":", "")),
|
||||
}
|
||||
else:
|
||||
state = {
|
||||
"situation": 3,
|
||||
"result": state["result"]
|
||||
}
|
||||
break
|
||||
else:
|
||||
pass
|
||||
return state["result"]
|
||||
|
||||
|
||||
7
source/helpers/string.py
Normal file
7
source/helpers/string.py
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
def coin(template, arguments):
|
||||
result = template
|
||||
for (key, value, ) in arguments.items():
|
||||
result = result.replace("{{%s}}" % key, value)
|
||||
return result
|
||||
|
||||
|
||||
62
source/verify.py
Normal file
62
source/verify.py
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
import sys as _sys
|
||||
import argparse as _argparse
|
||||
|
||||
import helpers.string as _string
|
||||
import helpers.certinfo as _certinfo
|
||||
|
||||
|
||||
def main():
|
||||
## args
|
||||
argument_parser = _argparse.ArgumentParser(
|
||||
prog = "tls-verify",
|
||||
description = "compares the fingerprints of a TLS certificate on the machine with the one delivered through the internet for a given domain",
|
||||
)
|
||||
argument_parser.add_argument(
|
||||
"domain",
|
||||
type = str,
|
||||
metavar = "<domain>",
|
||||
)
|
||||
argument_parser.add_argument(
|
||||
"-d",
|
||||
"--cert-directory",
|
||||
type = str,
|
||||
default = "/etc/ssl/fullchains",
|
||||
metavar = "<cert-directory>",
|
||||
)
|
||||
argument_parser.add_argument(
|
||||
"-e",
|
||||
"--file-extension",
|
||||
type = str,
|
||||
default = "pem",
|
||||
metavar = "<file-extension>",
|
||||
)
|
||||
args = argument_parser.parse_args()
|
||||
|
||||
## exec
|
||||
fingerprint_shall = _certinfo.extract_fingerprint(
|
||||
_certinfo.get_certificate_info_from_file(
|
||||
_string.coin(
|
||||
"{{directory}}/{{domain}}.{{extension}}",
|
||||
{
|
||||
"directory": args.cert_directory,
|
||||
"domain": args.domain,
|
||||
"extension": args.file_extension
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
fingerprint_is = _certinfo.extract_fingerprint(
|
||||
_certinfo.get_certificate_info_from_internet(
|
||||
args.domain
|
||||
)
|
||||
)
|
||||
if (fingerprint_shall == fingerprint_is):
|
||||
_sys.stdout.write("ok\n")
|
||||
_sys.exit(0)
|
||||
else:
|
||||
_sys.stderr.write("!MISMATCH!\n")
|
||||
_sys.stderr.write("[shall] %s\n" % fingerprint_shall)
|
||||
_sys.stderr.write("[is ] %s\n" % fingerprint_is)
|
||||
_sys.exit(1)
|
||||
|
||||
|
||||
36
tools/build
Executable file
36
tools/build
Executable file
|
|
@ -0,0 +1,36 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
## consts
|
||||
|
||||
dir_source="source"
|
||||
dir_temp="/tmp/tls-utils-temp"
|
||||
dir_build="/tmp/tls-utils"
|
||||
|
||||
|
||||
## vars
|
||||
|
||||
path_verify=${dir_build}/tls-verify
|
||||
|
||||
|
||||
## exec
|
||||
|
||||
### exec:verify
|
||||
|
||||
rm ${dir_temp} --force --recursive
|
||||
mkdir ${dir_temp} --parents
|
||||
cp ${dir_source}/. ${dir_temp}/ --recursive --update --verbose
|
||||
for dir in $(find ${dir_temp} -mindepth 1 -type d) ; do touch ${dir}/__init__.py ; done
|
||||
echo '' > ${dir_temp}/__main__.py
|
||||
echo 'from verify import *' >> ${dir_temp}/__main__.py
|
||||
echo 'if __name__ == "__main__": main()' >> ${dir_temp}/__main__.py
|
||||
|
||||
mkdir ${dir_build} --parents
|
||||
# rm ${path_verify}.zip --force
|
||||
cd ${dir_temp}
|
||||
python3 -m zipfile -c ${path_verify}.zip .
|
||||
cd -
|
||||
echo '#!/usr/bin/env python3' > ${path_verify}
|
||||
cat ${path_verify}.zip >> ${path_verify}
|
||||
rm ${path_verify}.zip
|
||||
chmod +x ${path_verify}
|
||||
|
||||
Loading…
Reference in a new issue