# LoadPrivateKey.java

    /*
    ** Module   : LoadPrivateKey.java
    ** Abstract : loads one or more private keys into the directory.
    **
    ** Copyright (c) 2021, Golden Code Development Corporation.
    **
    ** -#- -I- --Date-- ----------------------------------------Description---------------------------------------
    ** 001 CA  20210917 Created the initial version.
    */

    /*
    ** This program is free software: you can redistribute it and/or modify
    ** it under the terms of the GNU Affero General Public License as
    ** published by the Free Software Foundation, either version 3 of the
    ** License, or (at your option) any later version.
    **
    ** This program is distributed in the hope that it will be useful,
    ** but WITHOUT ANY WARRANTY; without even the implied warranty of
    ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    ** GNU Affero General Public License for more details.
    **
    ** You may find a copy of the GNU Affero GPL version 3 at the following
    ** location: https://www.gnu.org/licenses/agpl-3.0.en.html
    **
    ** Additional terms under GNU Affero GPL version 3 section 7:
    **
    **   Under Section 7 of the GNU Affero GPL version 3, the following additional
    **   terms apply to the works covered under the License.  These additional terms
    **   are non-permissive additional terms allowed under Section 7 of the GNU
    **   Affero GPL version 3 and may not be removed by you.
    **
    **   0. Attribution Requirement.
    **
    **     You must preserve all legal notices or author attributions in the covered
    **     work or Appropriate Legal Notices displayed by works containing the covered
    **     work.  You may not remove from the covered work any author or developer
    **     credit already included within the covered work.
    **
    **   1. No License To Use Trademarks.
    **
    **     This license does not grant any license or rights to use the trademarks
    **     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
    **     of Golden Code Development Corporation. You are not authorized to use the
    **     name Golden Code, FWD, or the names of any author or contributor, for
    **     publicity purposes without written authorization.
    **
    **   2. No Misrepresentation of Affiliation.
    **
    **     You may not represent yourself as Golden Code Development Corporation or FWD.
    **
    **     You may not represent yourself for publicity purposes as associated with
    **     Golden Code Development Corporation, FWD, or any author or contributor to
    **     the covered work, without written authorization.
    **
    **   3. No Misrepresentation of Source or Origin.
    **
    **     You may not represent the covered work as solely your work.  All modified
    **     versions of the covered work must be marked in a reasonable way to make it
    **     clear that the modified work is not originating from Golden Code Development
    **     Corporation or FWD.  All modified versions must contain the notices of
    **     attribution required in this license.
    */

    package com.goldencode.p2j.util;

    import java.io.*;
    import java.security.*;

    import com.goldencode.p2j.cfg.*;
    import com.goldencode.p2j.directory.*;
    import com.goldencode.p2j.security.*;

    /**
     * Adds new or replaces existing private keys in the directory.
     */
    public class LoadPrivateKey
    {
       /**
        * Creates or replaces a private key under a specified name.
        *
        * @param    directory
        *           The instance of directory to write to.
        * @param    oid
        *           The object ID for the directory object.
        * @param    file
        *           A JKS key-store to read the private-key from.
        * @param    alias
        *           The alias to load from the file.
        * @param    kspassword
        *           The key store password.
        * @param    kepassword
        *           The key entry password.
        */
       private static boolean loadSingle(DirectoryService directory,
                                         String           oid,
                                         String           file,
                                         String           alias,
                                         String           kspassword,
                                         String           kepassword)
       {
          File pkf = new File(file);

          if (!pkf.exists())
          {
             System.err.println("JKS store file " + file + " not found");
             return false;
          }

          byte[] encrypted = null;
          String dirPassword = null;

          try
          {
             SSLCertFactory factory = SSLCertGenUtil.getFactory();

             KeyStore ks = KeyStore.getInstance("JKS");
             ks.load(new FileInputStream(pkf), kspassword.toCharArray());

             Key key = ks.getKey(alias, kepassword.toCharArray());
             dirPassword = SSLCertGenUtil.createAES256BitKey();
             encrypted = factory.encryptPrivateKey(key, dirPassword);
          }

          catch (Exception e)
          {
             System.err.println(e);
             return false;
          }

          // save the private key
          {
             String nodeId = oid + "/key-entry";
             // check for existing node
             String nodeClass = directory.getNodeClass(nodeId);
             if (nodeClass != null)
             {
                boolean res = directory.deleteNode(nodeId);
                if (!res)
                {
                   return false;
                }
             }

             // create directory object
             Attribute[] data = new Attribute[]
             {
                // private-key data: value (bytearray)
                new Attribute(directory.getClassNodeAttribute("bytes", "value"), new Object[] { encrypted }),
             };

             if (!directory.addNode(nodeId, "bytes", data))
             {
                return false;
             }
          }

          // save the encryption password
          {
             String nodeId = oid + "/key-password";
             String nodeClass = directory.getNodeClass(nodeId);
             if (nodeClass != null)
             {
                boolean res = directory.deleteNode(nodeId);
                if (!res)
                {
                   return false;
                }
             }

             // create directory object
             Attribute[] data = new Attribute[]
             {
                // encryption data: value (bytearray)
                new Attribute(directory.getClassNodeAttribute("bytes", "value"),
                              new Object[] { dirPassword.getBytes() }),
             };

             if (!directory.addNode(nodeId, "bytes", data))
             {
                return false;
             }
          }

          return true;
       }

       /**
        * Command line driver.
        *
        * @param    args
        *           Application command line parameters.
        *
        * @throws   ConfigurationException
        *           In case of errors in configuration file.
        */
       public static void main(String[] args)
       throws ConfigurationException
       {
          char[] pass  = null;
          String conf  = null;
          boolean syntax = false;

          if (args.length < 5 || (args[0].endsWith(".xml") && args.length == 2))
          {
             syntax = true;
          }

          if (syntax)
          {
             System.out.println("usage: java LoadPrivateKey " +
                                "[<config.xml> { <password> | - } ] node file alias kspassword kepassword ...");
             return;
          }

          BootstrapConfig bc = null;
          int start = 0;

          if (args[0].endsWith(".xml"))
          {
             conf = args[0];
             start = 2;

             if (!args[1].equals("-"))
                pass = args[1].toCharArray();
          }
          else
             conf = "standard_server.xml";

          bc = new BootstrapConfig(conf, pass, null, null);

          System.out.println("Instantiating DirectoryService");
          DirectoryService dir = DirectoryService.createInstance(bc);
          System.out.println("DirectoryService is up");

          System.out.println("Binding to directory.");
          if (!dir.bind())
          {
             throw new RuntimeException("bind() failed");
          }
          System.out.println("Bound to directory.");

          System.out.println("Opening an editing batch...");
          if (!dir.openBatch("/security/certificates"))
          {
             throw new RuntimeException("openBatch() failed");
          }
          System.out.println("Opened an editing batch for /security/certificates");

          // perform certificates load

          for (int i = start; i < args.length; i += 5)
          {
             boolean res = loadSingle(dir, args[i], args[i + 1], args[i + 2], args[i + 3], args[i + 4]);
             if (res)
             {
                System.out.print("  loaded ");
             }
             else
             {
                System.out.print("* failed ");
             }
             System.out.println(args[i] + " from " + args[i + 1] + "[" + args[i + 2] + "]");
          }

          //----------------------------------------------------------------------
          // all done

          System.out.println("Closing the batch...");
          if (!dir.closeBatch(true))
          {
             throw new RuntimeException("closeBatch() failed");
          }
          System.out.println("Batch closed.");
          System.out.println("Unbinding from directory...");
          if (!dir.unbind())
          {
             throw new RuntimeException("unbind() failed");
          }
          System.out.println("Unbound.");

          System.out.println("Done.");
       }
    }