/******************************************************************************* * Copyright (C) 2026, Leo Galambos * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. All advertising materials mentioning features or use of this software must * display the following acknowledgement: * This product includes software developed by the Egothor project. * * 4. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ package zeroecho; import java.io.IOException; import java.security.GeneralSecurityException; import java.util.Arrays; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.MissingOptionException; import org.apache.commons.cli.Option; import org.apache.commons.cli.OptionGroup; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.commons.cli.help.HelpFormatter; import zeroecho.sdk.util.BouncyCastleActivator; import zeroecho.pki.cli.PkiCli; /** * ZeroEcho is a command-line utility for managing asymmetric keys and * certificates, primarily focusing on Certificate Authority (CA) operations * such as issuing, revoking, and listing certificates. *

* It supports command-line options for asymmetric key management, including * issuing certificates from CSRs or subject names, revoking certificates, and * retrieving all certificates for a user. *

*

* This class initializes Bouncy Castle security provider and uses Apache * Commons CLI for command-line parsing. *

* * @author Leo Galambos */ public final class ZeroEcho { /** * Logger instance for the {@code ZeroEcho} class used to log messages and * events. *

* This logger is configured with the name of the {@code ZeroEcho} class, * allowing for fine-grained logging control specific to this class. *

*/ public static final Logger LOG = Logger.getLogger(ZeroEcho.class.getName()); static { BouncyCastleActivator.init(); } /** * Default constructor for ZeroEcho. *

* This constructor does not perform any initialization since all operations are * handled via static methods and blocks. *

*/ private ZeroEcho() { // No initialization needed } /** * Main entry point for the ZeroEcho application. Parses command-line arguments * and dispatches to the appropriate subcommand for asymmetric key management or * prints the help message. * * @param args command-line arguments passed to the program * @throws IOException If the output could not be written */ public static void main(final String[] args) throws IOException { final int errorCode = mainProcess(args); if (args.length > 0 && "pki".equals(args[0])) { if (errorCode != 0) { System.exit(errorCode); } return; } if (errorCode == 0) { System.out.println("OK"); } else { System.out.println("ERR: " + errorCode); } } /** * Entry point for the ZeroEcho application. Parses command-line arguments and * dispatches to the appropriate subcommand for asymmetric key management or * prints the help message. * * @param args command-line arguments passed to the program * @return error-code * @throws IOException If the output could not be written */ public static int mainProcess(final String... args) throws IOException { if (args.length > 0 && "pki".equals(args[0])) { return PkiCli.execute(Arrays.copyOfRange(args, 1, args.length), System.out); } final Option KEM_OPTION = Option.builder("E").longOpt("kem").desc("KEM encryption/decryption").get(); final Option GUARD_OPTION = Option.builder("G").longOpt("guard") .desc("multi-recipient encryption/decryption (keys+passwords), AES/ChaCha").get(); final Option KEYSTORE_OPTION = Option.builder("K").longOpt("ksm").desc("key store management").get(); final Option COVERT_OPTION = Option.builder("C").longOpt("covert").desc("covert channel processing").get(); final Option TAG_OPTION = Option.builder("T").longOpt("tag") .desc("tag subcommand (signature/digest; produce/verify)").get(); final OptionGroup OPERATION_GROUP = new OptionGroup(); OPERATION_GROUP.addOption(GUARD_OPTION); OPERATION_GROUP.addOption(KEYSTORE_OPTION); OPERATION_GROUP.addOption(KEM_OPTION); OPERATION_GROUP.addOption(COVERT_OPTION); OPERATION_GROUP.addOption(TAG_OPTION); OPERATION_GROUP.setRequired(true); // At least one required Options options = new Options(); options.addOptionGroup(OPERATION_GROUP); final CommandLineParser parser = new DefaultParser(); try { // parse the command line arguments (allow remaining arguments for subcommands) parser.parse(options, args, true); return switch (OPERATION_GROUP.getSelected()) { case "E" -> Kem.main(args, options = new Options().addOption(KEM_OPTION)); case "G" -> Guard.main(args, options = new Options().addOption(GUARD_OPTION)); case "K" -> KeyStoreManagement.main(args, options = new Options().addOption(KEYSTORE_OPTION)); case "C" -> CovertCommand.main(args, options = new Options().addOption(COVERT_OPTION)); case "T" -> Tag.main(args, options = new Options().addOption(TAG_OPTION)); default -> 1; }; } catch (MissingOptionException ex) { if (LOG.isLoggable(Level.SEVERE)) { LOG.log(Level.SEVERE, ex.getMessage()); } return help(options); } catch (ParseException | GeneralSecurityException ex) { if (LOG.isLoggable(Level.WARNING)) { LOG.log(Level.WARNING, "Unexpected exception", ex.getMessage()); } return help(options); } catch (IOException e) { LOG.logp(Level.WARNING, "ZeroEcho", "mainProcess", e.getMessage(), e); return -1; } finally { LOG.log(Level.INFO, "Completed."); } } /** * Prints the usage help message for the command-line interface of the ZeroEcho * application. * *

* This method automatically generates and displays a help statement based on * the provided command-line {@link Options}. It then terminates the program * with exit status {@code 1}. * * @param options The {@link Options} instance defining the available * command-line options. * @return always {@code 1} * @throws IOException If the output could not be written */ private static int help(final Options options) throws IOException { // automatically generate the help statement final HelpFormatter formatter = HelpFormatter.builder().get(); formatter.printHelp(ZeroEcho.class.getName(), "", options, "", false); return 1; } }