feat: Add generate-mobileconfig.py script for creating Apple mobileconfig profiles
/ test-bash (push) Successful in 13s
/ test-python (push) Successful in 48s
/ test-go (push) Successful in 10m9s

This commit is contained in:
2026-05-24 12:50:03 +02:00
parent b28354e41c
commit e342c4ced7
4 changed files with 291 additions and 6 deletions
+17 -6
View File
@@ -29,6 +29,8 @@ import re
import subprocess
import sys
OPENSSL = "openssl"
def _err(msg):
print(f"ERROR: {msg}", file=sys.stderr)
@@ -95,7 +97,7 @@ def make_ca(ca_dir, ca_name, days=3650, issuing_ca=None, aia_base_url=None):
# one level of issuing CAs, but prevent a longer chain which is not
# supported by this script.
cmd = [
"openssl", "req",
OPENSSL, "req",
"-x509",
"-newkey", "rsa:4096",
"-keyout", root_ca_key_path,
@@ -122,7 +124,7 @@ def make_ca(ca_dir, ca_name, days=3650, issuing_ca=None, aia_base_url=None):
if not os.path.isfile(ca_cert_path) or not os.path.isfile(ca_key_path):
print(f"Generating issuing CA certificate '{ca_name}' and key...")
req_cmd = [
"openssl", "req",
OPENSSL, "req",
"-newkey", "rsa:4096",
"-keyout", ca_key_path,
"-noenc",
@@ -136,7 +138,7 @@ def make_ca(ca_dir, ca_name, days=3650, issuing_ca=None, aia_base_url=None):
f"authorityInfoAccess=caIssuers;URI:{aia_base_url}/ca_cert.crt",
]
x509_cmd = [
"openssl", "x509",
OPENSSL, "x509",
"-req",
"-CA", root_ca_cert_path,
"-CAkey", root_ca_key_path,
@@ -247,7 +249,7 @@ def make_cert(cert_dir, cert_subject_name, sans=None, ca_dir=None,
if not os.path.isfile(cert_out) or not os.path.isfile(key_out):
print("Generating server certificate and key...")
req_cmd = [
"openssl", "req",
OPENSSL, "req",
"-newkey", "rsa:4096",
"-keyout", key_out,
"-noenc",
@@ -260,7 +262,7 @@ def make_cert(cert_dir, cert_subject_name, sans=None, ca_dir=None,
if aia_url:
req_cmd += ["-addext", f"authorityInfoAccess=caIssuers;URI:{aia_url}"]
x509_cmd = [
"openssl", "x509",
OPENSSL, "x509",
"-req",
"-CA", ca_cert_path,
"-CAkey", ca_key_path,
@@ -343,7 +345,7 @@ def make_pfx(cert_path, ca_dir, issuing_ca=None, password=None):
with os.fdopen(chain_fd, "wb") as f:
f.write(chain_bytes)
cmd = [
"openssl", "pkcs12",
OPENSSL, "pkcs12",
"-export", "-out", pfx_path,
"-inkey", key_path,
"-in", cert_path,
@@ -372,6 +374,8 @@ def _build_parser():
p_ca.add_argument("--issuing-ca", help="Specify the issuing CA")
p_ca.add_argument("--aia-base-url", help="Specify the AIA base URL")
p_ca.add_argument("--ca-dir", help="Directory to store the CA files")
p_ca.add_argument("--openssl", default=OPENSSL, metavar="PATH",
help=f"Path to the openssl binary (default: {OPENSSL})")
p_ca.add_argument("ca_name", help="Name of the CA")
p_cert = sub.add_parser("make-cert", help="Create a server/client certificate.")
@@ -379,6 +383,8 @@ def _build_parser():
p_cert.add_argument("--issuing-ca", help="Specify the issuing CA")
p_cert.add_argument("--days", type=int, default=365, help="Validity period in days (default: 365)")
p_cert.add_argument("--cert-dir", help="Directory to store the certificate files")
p_cert.add_argument("--openssl", default=OPENSSL, metavar="PATH",
help=f"Path to the openssl binary (default: {OPENSSL})")
p_cert.add_argument("subject_name", help="Subject name for the certificate")
p_cert.add_argument("sans", nargs="*", help="Subject Alternative Names (SANs) for the certificate")
@@ -386,14 +392,19 @@ def _build_parser():
p_pfx.add_argument("--issuing-ca", help="Specify the issuing CA")
p_pfx.add_argument("--ca-dir", help="Directory of the CA")
p_pfx.add_argument("--password", help="Password for the PFX file")
p_pfx.add_argument("--openssl", default=OPENSSL, metavar="PATH",
help=f"Path to the openssl binary (default: {OPENSSL})")
p_pfx.add_argument("path", help="Path to the certificate file")
return parser
def main(argv=None):
global OPENSSL
parser = _build_parser()
args = parser.parse_args(argv)
OPENSSL = args.openssl
ca_dir = args.ca_dir or os.environ.get("SIMPLE_CA_DIR") or os.getcwd()
if args.command == "make-ca":