From b793303a7d4548e2cc8f85b657655db646d93bea Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jul 21 2021 07:56:10 +0000 Subject: Merge #54 `koji-ssl-admin: write combined ".cert" file for users` --- diff --git a/src/bin/koji-ssl-admin b/src/bin/koji-ssl-admin index f3e5608..de223ca 100755 --- a/src/bin/koji-ssl-admin +++ b/src/bin/koji-ssl-admin @@ -51,10 +51,10 @@ Common Koji SSL admin operations: in your environment. (For example, in a testing environment.) You can use this to sign server certs or user certs with your CA. For user certs, if you have the private key in the same directory, this - will also generate a "user_browser_cert.p12" bundle for your browser to log - into Kojiweb. + will also generate a "user.cert" combined file for the CLI and a + "user_browser_cert.p12" bundle for your browser to log into Kojiweb. -Never share the .key or .p12 files or post them in a public location. +Never share the .key, .cert, or .p12 files or post them in a public location. """ @@ -323,6 +323,29 @@ def is_client_cert(certificate): return eku.value == client_auth +def write_user_cert(crt_path, key_path, cert_path, force): + """ + Concatenate the user's public cert and private key into a single "cert" + file. The koji CLI expects this file format for Koji's "cert = FILE" + config file option for your koji profile (or the "--cert=FILE" + command-line option.) + + :param str crt_path: path to the server public certificate + :param str key_path: path to .key file + :param str cert_path: path on disk to write the private .cert file + :param bool force: overwrite the .cert file if it already exists + """ + if os.path.exists(cert_path) and not force: + raise OSError(errno.EEXIST, os.strerror(errno.EEXIST), cert_path) + flags = os.O_WRONLY | os.O_CREAT + mode = 0o600 + with os.fdopen(os.open(cert_path, flags, mode), 'w') as fout: + fin = fileinput.input([crt_path, key_path]) + for line in fin: + fout.write(line) + fin.close() + + def write_pkcs12(crt_path, key_path, ca_crt_path, pkcs12_path, force): """ Write out a private pkcs12 keypair with a password of "koji". @@ -396,18 +419,22 @@ def sign(args): # directory, then generate a pkcs12 bundle file with the cert and key. key_path = re.sub(r'\.csr$', '.key', csr_path) if is_client_cert(cert) and os.path.exists(key_path): - bundle_user_browser_cert(crt_path, key_path, ca_crt_path, force) + bundle_user_cert(crt_path, key_path, ca_crt_path, force) # If this is a server cert, create the SSL cert chain file if not is_client_cert(cert): build_cert_chain_file(crt_path, ca_crt_path, force) -def bundle_user_browser_cert(crt_path, key_path, ca_crt_path, force): +def bundle_user_cert(crt_path, key_path, ca_crt_path, force): """ - Combine a user's public .crt file and matching .key file into one file. + Combine a user's public .crt file and matching .key into "bundle" files. + Use the .cert file to log in with the koji CLI. Use the .pkcs12 bundle file to log into Kojiweb. """ + cert_path = re.sub(r'\.key$', '.cert', key_path) + write_user_cert(crt_path, key_path, cert_path, force) + print('wrote %s for koji CLI - protect this private file' % cert_path) pkcs12_path = re.sub(r'\.key$', '_browser_cert.p12', key_path) write_pkcs12(crt_path, key_path, ca_crt_path, pkcs12_path, force) print('wrote %s for kojiweb - protect this private file' % pkcs12_path)