From 3936cbf9558b9269469be1d6b68d87ddef776b3e Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Tue, 9 Jan 2024 15:30:52 +0000 Subject: [PATCH] scripts: add criu-keygen script This script, similar to ssh-keygen and certtool, makes it easier to generate and install certificate and key to enable encryption support with CRIU. Signed-off-by: Radostin Stoyanov --- Documentation/Makefile | 1 + Documentation/criu-keygen.txt | 29 +++++++++++ Makefile | 1 + criu/Makefile | 3 ++ scripts/criu-keygen | 96 +++++++++++++++++++++++++++++++++++ 5 files changed, 130 insertions(+) create mode 100644 Documentation/criu-keygen.txt create mode 100755 scripts/criu-keygen diff --git a/Documentation/Makefile b/Documentation/Makefile index de0cc448dc..f6f6778887 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -13,6 +13,7 @@ endif FOOTER := footer.txt SRC1 += crit.txt SRC1 += criu-ns.txt +SRC1 += criu-keygen.txt SRC1 += compel.txt SRC1 += criu-amdgpu-plugin.txt SRC8 += criu.txt diff --git a/Documentation/criu-keygen.txt b/Documentation/criu-keygen.txt new file mode 100644 index 0000000000..76f5faa450 --- /dev/null +++ b/Documentation/criu-keygen.txt @@ -0,0 +1,29 @@ +CRIU-KEYGEN(1) +============== +include::footer.txt[] + +NAME +---- +criu-keygen - criu encryption key utility + +SYNOPSIS +-------- +*criu-keygen* [] + +DESCRIPTION +----------- +The *criu-keygen* command generates and manages encryption keys for CRIU. +*criu-keygen* can create keys for use by CRIU. The type of key to be +generated is specified with the *-t* option. If invoked without any arguments, +*criu-keygen* will generate an RSA keys. + +A system administrator wishing to use CRIU with encryption, would run *criu-keygen* +once to create a certficicate and private key in '/etc/pki/criu/'. + +SEE ALSO +-------- +criu(8) + +AUTHOR +------ +The CRIU team diff --git a/Makefile b/Makefile index 172d4b5177..70700ef18f 100644 --- a/Makefile +++ b/Makefile @@ -455,6 +455,7 @@ ruff: lib/pycriu/images/images.py \ scripts/criu-ns \ test/others/criu-ns/run.py \ + scripts/criu-keygen \ crit/*.py \ crit/crit/*.py \ scripts/uninstall_module.py \ diff --git a/criu/Makefile b/criu/Makefile index bafdd980bb..c5d2f422e6 100644 --- a/criu/Makefile +++ b/criu/Makefile @@ -147,12 +147,15 @@ install: $(obj)/criu $(Q) install -m 755 scripts/systemd-autofs-restart.sh $(DESTDIR)$(LIBEXECDIR)/criu/scripts $(E) " INSTALL " scripts/criu-ns $(Q) install -m 755 scripts/criu-ns $(DESTDIR)$(SBINDIR) + $(E) " INSTALL " scripts/criu-keygen + $(Q) install -m 755 scripts/criu-keygen $(DESTDIR)$(SBINDIR) .PHONY: install uninstall: $(E) " UNINSTALL" criu $(Q) $(RM) $(addprefix $(DESTDIR)$(SBINDIR)/,criu) $(Q) $(RM) $(addprefix $(DESTDIR)$(SBINDIR)/,criu-ns) + $(Q) $(RM) $(addprefix $(DESTDIR)$(SBINDIR)/,criu-keygen) $(Q) $(RM) $(addprefix $(DESTDIR)$(INCLUDEDIR)/criu/,$(notdir $(UAPI_HEADERS))) $(Q) $(RM) $(addprefix $(DESTDIR)$(LIBEXECDIR)/criu/scripts/,systemd-autofs-restart.sh) .PHONY: uninstall diff --git a/scripts/criu-keygen b/scripts/criu-keygen new file mode 100755 index 0000000000..6124f363a2 --- /dev/null +++ b/scripts/criu-keygen @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 +import os +import argparse +import datetime +import pathlib + +from cryptography import x509 +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import rsa +from cryptography.hazmat.primitives.asymmetric import ec + +CRIU_PKI_PATH = "/etc/pki/criu" +CRIU_KEY_PATH = "/etc/pki/criu/private" + + +def generate_certificate(private_key): + """ + Generate x509 certificate from private key and save + them in the default PKI path. + """ + key_path = input("Enter file in which to save the key ({}): ".format( + os.path.join(CRIU_KEY_PATH, "key.pem") + )) + if not key_path: + key_path = os.path.join(CRIU_KEY_PATH, "key.pem") + + cert_path = input("Enter file in which to save the certificate ({}): ".format( + os.path.join(CRIU_PKI_PATH, "cert.pem") + )) + if not cert_path: + cert_path = os.path.join(CRIU_PKI_PATH, "cert.pem") + + subject = issuer = x509.Name([]) + cert = ( + x509.CertificateBuilder() + .subject_name(subject) + .issuer_name(issuer) + .public_key(private_key.public_key()) + .serial_number(x509.random_serial_number()) + .not_valid_before(datetime.datetime.now(datetime.timezone.utc)) + .not_valid_after(datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(days=10)) + .sign(private_key, hashes.SHA256()) + ) + + pathlib.Path(CRIU_KEY_PATH).mkdir(parents=True, exist_ok=True) + + os.umask(0o277) + with open(key_path, "wb") as f: + f.write(private_key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=serialization.NoEncryption(), + )) + + os.umask(0o222) + with open(cert_path, "wb") as f: + f.write(cert.public_bytes(serialization.Encoding.PEM)) + + +def generate_ec_key(key_size): + """ + Create a self-signed certificate with an EC key. + """ + if not key_size: + key_size = 256 + print("Generating public/private ec key pair.") + private_key = ec.generate_private_key(ec.SECP256R1(key_size=key_size)) + generate_certificate(private_key) + + +def generate_rsa_key(key_size): + """ + Create a self-signed certificate with an RSA key. + """ + if not key_size: + key_size = 2048 + print("Generating public/private rsa key pair.") + private_key = rsa.generate_private_key(public_exponent=65537, key_size=key_size) + generate_certificate(private_key) + + +def main(): + parser = argparse.ArgumentParser(description='Generate X.509 certificates and private keys for CRIU.') + parser.add_argument('--type', choices=['rsa', 'ec'], default='rsa', help='Type of key to create (default: rsa)') + parser.add_argument('--bits', type=int, help='Number of bits in the key') + args = parser.parse_args() + + if args.type == 'rsa': + generate_rsa_key(args.bits) + elif args.type == 'ec': + generate_ec_key() + + +if __name__ == "__main__": + main()