#!/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()