132 lines
3.7 KiB
Python
132 lines
3.7 KiB
Python
#!/usr/bin/env python3
|
|
# dlitz 2025
|
|
|
|
import os
|
|
import shlex
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
from argparse import ArgumentParser
|
|
from pathlib import Path
|
|
|
|
from cryptography import x509
|
|
from cryptography.hazmat.primitives.serialization import (
|
|
load_pem_private_key,
|
|
load_pem_public_key,
|
|
)
|
|
|
|
from .connector import SSHConnector
|
|
from .routeros import RouterOS
|
|
|
|
|
|
def make_arg_parser():
|
|
if Path(sys.argv[0]).stem == "__main__":
|
|
prog = __package__
|
|
else:
|
|
prog = None
|
|
parser = ArgumentParser(
|
|
prog=prog,
|
|
description="push TLS privkey & certificate to MikroTik RouterOS router",
|
|
)
|
|
|
|
subparsers = parser.add_subparsers(dest="subcommand", required=True)
|
|
|
|
deploy_parser = subparsers.add_parser(
|
|
"deploy", help="deploy TLS privkey & certificate to MikroTik RouterOS router"
|
|
)
|
|
deploy_parser.add_argument("--ssh-config", type=Path, help="ssh config file")
|
|
deploy_parser.add_argument("--ssh-user", help="target ssh user")
|
|
deploy_parser.add_argument("--ssh-port", type=int, help="target ssh port")
|
|
deploy_parser.add_argument("--ssh-host", required=True, help="target ssh host")
|
|
deploy_parser.add_argument(
|
|
"-k", "--private-key", type=Path, required=True, help="PEM private key file"
|
|
)
|
|
deploy_parser.add_argument(
|
|
"--cert", type=Path, required=True, help="PEM certificate file"
|
|
)
|
|
deploy_parser.add_argument(
|
|
"--chain", type=Path, help="separate certificate chain file (optional)"
|
|
)
|
|
|
|
fingerprint_parser = subparsers.add_parser(
|
|
"fingerprint", aliases=["fpr"], help="calculate fingerprint of certificate(s)"
|
|
)
|
|
fingerprint_parser.add_argument(
|
|
dest="files",
|
|
metavar="cert.pem",
|
|
nargs="+",
|
|
type=Path,
|
|
help="PEM certificate file to read",
|
|
)
|
|
|
|
skid_parser = subparsers.add_parser(
|
|
"skid", help="show the SubjectKeyIdentifier of certificate(s)"
|
|
)
|
|
skid_parser.add_argument(
|
|
dest="files",
|
|
# metavar="file.pem",
|
|
metavar="cert.pem",
|
|
nargs="+",
|
|
type=Path,
|
|
# help="PEM file to read",
|
|
help="PEM certificate file to read",
|
|
)
|
|
|
|
return parser
|
|
|
|
|
|
def parse_args():
|
|
parser = make_arg_parser()
|
|
args = parser.parse_args()
|
|
return args, parser
|
|
|
|
|
|
def main():
|
|
args, parser = parse_args()
|
|
|
|
if args.subcommand == "deploy":
|
|
assert ":" not in args.ssh_host
|
|
|
|
privkey_data = args.private_key.read_text()
|
|
cert_data = args.cert.read_text()
|
|
chain_data = args.chain.read_text() if args.chain is not None else None
|
|
|
|
connector = SSHConnector(
|
|
host=args.ssh_host,
|
|
port=args.ssh_port,
|
|
user=args.ssh_user,
|
|
ssh_config_path=args.ssh_config,
|
|
)
|
|
ros_remote = RouterOS(connector=connector)
|
|
|
|
fingerprint, host_cert_obj = ros_remote.install_key_and_certificates(
|
|
key=privkey_data, cert=cert_data, chain=chain_data
|
|
)
|
|
|
|
ros_remote.use_certificate(fingerprint)
|
|
|
|
elif args.subcommand in ("fingerprint", "fpr"):
|
|
for path in args.files:
|
|
try:
|
|
for cert_obj in x509.load_pem_x509_certificates(path.read_bytes()):
|
|
print(RouterOS.cert_fingerprint(cert_obj))
|
|
except Exception as exc:
|
|
exc.add_note(f"path={path}")
|
|
raise
|
|
|
|
elif args.subcommand == "skid":
|
|
for path in args.files:
|
|
try:
|
|
for cert_obj in x509.load_pem_x509_certificates(path.read_bytes()):
|
|
print(RouterOS.cert_skid(cert_obj))
|
|
except Exception as exc:
|
|
exc.add_note(f"path={path}")
|
|
raise
|
|
|
|
else:
|
|
raise NotImplementedError(args.subcommand)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|