All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xipki.ca.mgmt.shell.CaActions Maven / Gradle / Ivy

The newest version!
// Copyright (c) 2013-2024 xipki. All rights reserved.
// License Apache License 2.0

package org.xipki.ca.mgmt.shell;

import org.apache.karaf.shell.api.action.Argument;
import org.apache.karaf.shell.api.action.Command;
import org.apache.karaf.shell.api.action.Completion;
import org.apache.karaf.shell.api.action.Option;
import org.apache.karaf.shell.api.action.lifecycle.Reference;
import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.apache.karaf.shell.support.completers.FileCompleter;
import org.xipki.ca.api.CaUris;
import org.xipki.ca.api.NameId;
import org.xipki.ca.api.mgmt.CaManager;
import org.xipki.ca.api.mgmt.CaMgmtException;
import org.xipki.ca.api.mgmt.CaProfileEntry;
import org.xipki.ca.api.mgmt.CaStatus;
import org.xipki.ca.api.mgmt.CrlControl;
import org.xipki.ca.api.mgmt.CtlogControl;
import org.xipki.ca.api.mgmt.Permissions;
import org.xipki.ca.api.mgmt.RevokeSuspendedControl;
import org.xipki.ca.api.mgmt.ValidityMode;
import org.xipki.ca.api.mgmt.entry.CaEntry;
import org.xipki.ca.api.mgmt.entry.CaHasRequestorEntry;
import org.xipki.ca.api.mgmt.entry.ChangeCaEntry;
import org.xipki.ca.api.mgmt.entry.PublisherEntry;
import org.xipki.security.CertRevocationInfo;
import org.xipki.security.CrlReason;
import org.xipki.security.SecurityFactory;
import org.xipki.security.X509Cert;
import org.xipki.security.util.X509Util;
import org.xipki.shell.CmdFailure;
import org.xipki.shell.Completers;
import org.xipki.shell.IllegalCmdParamException;
import org.xipki.shell.XiAction;
import org.xipki.util.Args;
import org.xipki.util.CollectionUtil;
import org.xipki.util.ConfPairs;
import org.xipki.util.DateUtil;
import org.xipki.util.IoUtil;
import org.xipki.util.StringUtil;
import org.xipki.util.Validity;

import java.io.File;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;

/**
 * Actions to manage CA.
 *
 * @author Lijun Liao (xipki)
 *
 */
public class CaActions {

  public abstract static class CaAction extends XiAction {

    @Reference
    protected CaManager caManager;

    @Reference
    protected SecurityFactory securityFactory;

    protected static Instant parseDate(String dateStr) {
      return StringUtil.isBlank(dateStr) ? null : DateUtil.parseUtcTimeyyyyMMddhhmmss(dateStr);
    }

    protected static String toString(Collection col) {
      if (col == null) {
        return "null";
      }

      StringBuilder sb = new StringBuilder().append("{");
      int size = col.size();

      int idx = 0;
      for (Object o : col) {
        sb.append(o);
        if (idx < size - 1) {
          sb.append(", ");
        }
        idx++;
      }
      sb.append("}");
      return sb.toString();
    } // method toString

    protected void printCaNames(StringBuilder sb, Set caNames, String prefix)
        throws CaMgmtException {
      if (caNames.isEmpty()) {
        sb.append(prefix).append("-\n");
        return;
      }

      for (String caName : caNames) {
        Set aliases = caManager.getAliasesForCa(caName);
        sb.append(prefix).append(caName);
        if (!CollectionUtil.isEmpty(aliases)) {
          sb.append(" (aliases ").append(aliases).append(")");
        }
        sb.append("\n");
      }
    } // method printCaNames

    protected Set getPublisherNamesForCa(String caName) throws CaMgmtException {
      Set publisherNames;
      try {
        publisherNames = caManager.getPublisherNamesForCa(caName);
      } catch (CaMgmtException ex) {
        // the server is v6.5.1 or before.
        List publishers = caManager.getPublishersForCa(caName);
        publisherNames = new HashSet<>();
        if (publishers != null) {
          for (PublisherEntry m : publishers) {
            publisherNames.add(m.getIdent().getName());
          }
        }
      }
      return publisherNames == null ? Collections.emptySet() : publisherNames;
    }

  } // class CaAction

  @Command(scope = "ca", name = "ca-add", description = "add CA")
  @Service
  public static class CaAdd extends CaAddOrGenAction {

    @Option(name = "--cert", description = "CA certificate file")
    @Completion(FileCompleter.class)
    private String certFile;

    @Option(name = "--certchain", multiValued = true, description = "certificate chain of CA certificate")
    @Completion(FileCompleter.class)
    private List issuerCertFiles;

    @Override
    protected Object execute0() throws Exception {
      CaEntry caEntry = getCaEntry();
      if (certFile != null) {
        caEntry.setCert(X509Util.parseCert(new File(certFile)));
      }

      if (CollectionUtil.isNotEmpty(issuerCertFiles)) {
        List list = new ArrayList<>(issuerCertFiles.size());
        for (String m : issuerCertFiles) {
          list.add(X509Util.parseCert(Paths.get(m).toFile()));
        }
        caEntry.setCertchain(list);
      }

      String msg = "CA " + caEntry.getIdent().getName();
      try {
        caManager.addCa(caEntry);
        println("added " + msg);
        return null;
      } catch (CaMgmtException ex) {
        throw new CmdFailure("could not add " + msg + ", error: " + ex.getMessage(), ex);
      }
    } // method execute0

  } // class CaAdd

  public abstract static class CaAddOrGenAction extends CaAction {

    @Option(name = "--name", aliases = "-n", required = true, description = "CA name")
    private String caName;

    @Option(name = "--status", description = "CA status")
    @Completion(CaCompleters.CaStatusCompleter.class)
    private String caStatus = "active";

    @Option(name = "--ca-cert-uri", multiValued = true, description = "CA certificate URI")
    private List caCertUris;

    @Option(name = "--ocsp-uri", multiValued = true, description = "OCSP URI")
    private List ocspUris;

    @Option(name = "--crl-uri", multiValued = true, description = "CRL distribution point")
    private List crlUris;

    @Option(name = "--deltacrl-uri", multiValued = true, description = "Delta CRL distribution point")
    private List deltaCrlUris;

    @Option(name = "--permission", required = true, multiValued = true, description = "permission")
    @Completion(CaCompleters.PermissionCompleter.class)
    private Set permissions;

    @Option(name = "--sn-len", description = "number of bytes of the serial number, between "
            + CaManager.MIN_SERIALNUMBER_SIZE + " and " + CaManager.MAX_SERIALNUMBER_SIZE)
    private int snLen = CaManager.MAX_SERIALNUMBER_SIZE;

    @Option(name = "--next-crl-no", required = true, description = "CRL number for the next CRL")
    private Long nextCrlNumber;

    @Option(name = "--max-validity", required = true, description = "maximal validity")
    private String maxValidity;

    @Option(name = "--keep-expired-certs", description = "days to keep expired certificates")
    private Integer keepExpiredCertDays = -1;

    @Option(name = "--crl-signer", description = "CRL signer name")
    @Completion(CaCompleters.SignerNameCompleter.class)
    private String crlSignerName;

    @Option(name = "--keypair-gen", multiValued = true, description = "(ordered) keypair generation names")
    @Completion(CaCompleters.KeypairGenNameCompleter.class)
    private List keypairGenNames;

    @Option(name = "--crl-control", description = "CRL control")
    private String crlControl;

    @Option(name = "--ctlog-control", description = "CT log control")
    private String ctlogControl;

    @Option(name = "--revoke-suspended-control",
        description = "Revoke suspended certificates control")
    private String revokeSuspendedControl;

    @Option(name = "--num-crls", description = "number of CRLs to be kept in database")
    private Integer numCrls = 30;

    @Option(name = "--expiration-period", description = "days before expiration time of CA to issue certificates")
    private Integer expirationPeriod = 365;

    @Option(name = "--signer-type", required = true, description = "CA signer type")
    @Completion(CaCompleters.SignerTypeCompleter.class)
    private String signerType;

    @Option(name = "--signer-conf", required = true, description = "CA signer configuration")
    private String signerConf;

    @Option(name = "--save-cert", description = "whether to save the certificate")
    @Completion(Completers.YesNoCompleter.class)
    private String saveCertS = "yes";

    @Option(name = "--save-keypair", description = "whether to save the keypair generated by the CA")
    @Completion(Completers.YesNoCompleter.class)
    private String saveKeypairS = "no";

    @Option(name = "--validity-mode", description = "mode of valditity")
    @Completion(CaCompleters.ValidityModeCompleter.class)
    private String validityModeS = "STRICT";

    @Option(name = "--extra-control", description = "extra control")
    private String extraControl;

    protected CaEntry getCaEntry() throws Exception {
      Args.range(snLen, "snLen", CaManager.MIN_SERIALNUMBER_SIZE, CaManager.MAX_SERIALNUMBER_SIZE);

      if (nextCrlNumber < 1) {
        throw new IllegalCmdParamException("invalid CRL number: " + nextCrlNumber);
      }

      if (numCrls < 0) {
        throw new IllegalCmdParamException("invalid numCrls: " + numCrls);
      }

      if (expirationPeriod < 0) {
        throw new IllegalCmdParamException("invalid expirationPeriod: " + expirationPeriod);
      }

      if (StringUtil.orEqualsIgnoreCase(signerType, "PKCS12", "JCEKS")) {
        signerConf = ShellUtil.canonicalizeSignerConf(signerType, signerConf, securityFactory);
      }

      CaUris caUris = new CaUris(caCertUris, ocspUris, crlUris, deltaCrlUris);
      CaEntry entry = new CaEntry(new NameId(null, caName));

      entry.setSnSize(snLen);
      entry.setNextCrlNo(nextCrlNumber);
      entry.setSignerType(signerType);
      entry.setSignerConf(signerConf);
      entry.setCaUris(caUris);
      entry.setNumCrls(numCrls);
      entry.setExpirationPeriod(expirationPeriod);
      entry.setKeepExpiredCertDays(keepExpiredCertDays);
      entry.setSaveCert(isEnabled(saveCertS, true, "save-cert"));
      entry.setSaveKeypair(isEnabled(saveKeypairS, false, "save-keypair"));
      entry.setValidityMode(ValidityMode.forName(validityModeS));
      entry.setStatus(CaStatus.forName(caStatus));

      if (crlControl != null) {
        entry.setCrlControl(new CrlControl(crlControl));
      }

      if (ctlogControl != null) {
        entry.setCtlogControl(new CtlogControl(ctlogControl));
      }

      if (revokeSuspendedControl != null) {
        entry.setRevokeSuspendedControl(new RevokeSuspendedControl(new ConfPairs(revokeSuspendedControl)));
      }

      if (crlSignerName != null) {
        entry.setCrlSignerName(crlSignerName);
      }

      if (CollectionUtil.isNotEmpty(keypairGenNames)) {
        entry.setKeypairGenNames(keypairGenNames);
      }

      entry.setMaxValidity(Validity.getInstance(maxValidity));
      entry.setKeepExpiredCertDays(keepExpiredCertDays);
      entry.setPermissions(new Permissions(permissions));

      if (extraControl != null) {
        extraControl = extraControl.trim();
      }
      if (StringUtil.isNotBlank(extraControl)) {
        entry.setExtraControl(new ConfPairs(extraControl).unmodifiable());
      }
      return entry;
    } // method getCaEntry

  } // class CaAddOrGenAction

  @Command(scope = "ca", name = "caalias-add", description = "add CA alias")
  @Service
  public static class CaaliasAdd extends CaAction {

    @Option(name = "--ca", required = true, description = "CA name")
    @Completion(CaCompleters.CaNameCompleter.class)
    private String caName;

    @Option(name = "--alias", required = true, description = "CA alias")
    private String caAlias;

    @Override
    protected Object execute0() throws Exception {
      String msg = "CA alias " + caAlias + " associated with CA " + caName;
      try {
        caManager.addCaAlias(caAlias, caName);
        println("added " + msg);
        return null;
      } catch (CaMgmtException ex) {
        throw new CmdFailure("could not add " + msg + ", error: " + ex.getMessage(), ex);
      }
    } // method execute0

  } // class CaaliasAdd

  @Command(scope = "ca", name = "caalias-info", description = "show information of CA alias")
  @Service
  public static class CaaliasInfo extends CaAction {

    @Argument(index = 0, name = "alias", description = "CA alias")
    @Completion(CaCompleters.CaAliasCompleter.class)
    private String caAlias;

    @Override
    protected Object execute0() throws Exception {
      Set aliasNames = caManager.getCaAliasNames();

      StringBuilder sb = new StringBuilder();

      if (caAlias == null) {
        int size = aliasNames.size();

        if (size == 0 || size == 1) {
          sb.append((size == 0) ? "no" : "1").append(" CA alias is configured\n");
        } else {
          sb.append(size).append(" CA aliases are configured:\n");
        }

        List sorted = new ArrayList<>(aliasNames);
        Collections.sort(sorted);

        for (String aliasName : sorted) {
          sb.append("\t").append(aliasName).append("\n");
        }
      } else {
        if (aliasNames.contains(caAlias)) {
          sb.append(caAlias).append("\n\t").append(caManager.getCaNameForAlias(caAlias));
        } else {
          throw new CmdFailure("could not find CA alias '" + caAlias + "'");
        }
      }

      println(sb.toString());
      return null;
    } // method execute0

  } // class CaaliasInfo

  @Command(scope = "ca", name = "caalias-rm", description = "remove CA alias")
  @Service
  public static class CaaliasRm extends CaAction {

    @Argument(index = 0, name = "alias", description = "CA alias", required = true)
    @Completion(CaCompleters.CaAliasCompleter.class)
    private String caAlias;

    @Option(name = "--force", aliases = "-f", description = "without prompt")
    private Boolean force = Boolean.FALSE;

    @Override
    protected Object execute0() throws Exception {
      String msg = "CA alias " + caAlias;
      if (force || confirm("Do you want to remove " + msg, 3)) {
        try {
          caManager.removeCaAlias(caAlias);
          println("removed " + msg);
        } catch (CaMgmtException ex) {
          throw new CmdFailure("could not remove " + msg + ", error: " + ex.getMessage(), ex);
        }
      }
      return null;
    } // method execute0

  } // class CaaliasRm

  @Command(scope = "ca", name = "gen-rootca", description = "generate selfsigned CA")
  @Service
  public static class GenRootca extends CaAddOrGenAction {

    @Option(name = "--subject", required = true, description = "subject of the Root CA")
    private String subject;

    @Option(name = "--profile", required = true, description = "profile of the Root CA")
    private String rootcaProfile;

    @Option(name = "--serial", description = "serial number of the Root CA")
    private String serialS;

    @Option(name = "--not-before", description = "notBefore, UTC time of format yyyyMMddHHmmss")
    private String notBeforeS;

    @Option(name = "--not-after", description = "notAfter, UTC time of format yyyyMMddHHmmss")
    private String notAfterS;

    @Option(name = "--outform", description = "output format of the certificate")
    @Completion(Completers.DerPemCompleter.class)
    protected String outform = "der";

    @Option(name = "--out", aliases = "-o", description = "where to save the generated CA certificate")
    @Completion(FileCompleter.class)
    private String rootcaCertOutFile;

    @Override
    protected Object execute0() throws Exception {
      CaEntry caEntry = getCaEntry();
      Instant notBefore = parseDate(notBeforeS);
      Instant notAfter = parseDate(notAfterS);
      X509Cert rootcaCert = caManager.generateRootCa(caEntry, rootcaProfile, subject, serialS, notBefore, notAfter);
      if (rootcaCertOutFile != null) {
        saveVerbose("saved root certificate to file", rootcaCertOutFile,
            encodeCert(rootcaCert.getEncoded(), outform));
      }
      println("generated root CA " + caEntry.getIdent().getName());
      return null;
    } // method execute0

  } // class GenRootca

  @Command(scope = "ca", name = "cacert", description = "get CA's certificate")
  @Service
  public static class CaCert extends CaAction {

    @Argument(name = "name", required = true, description = "CA name")
    @Completion(CaCompleters.CaNameCompleter.class)
    private String name;

    @Option(name = "--outform", description = "output format of the certificate")
    @Completion(Completers.DerPemCompleter.class)
    protected String outform = "der";

    @Option(name = "--out", aliases = "-o", required = true,
        description = "where to save the certificate file")
    @Completion(FileCompleter.class)
    protected String outFile;

    @Override
    protected Object execute0() throws Exception {
      List certs = caManager.getCaCerts(name);
      if ("der".equalsIgnoreCase(outform)) {
        IoUtil.save(outFile, certs.get(0).getEncoded());
      } else if ("pem".equalsIgnoreCase(outform)) {
        IoUtil.save(outFile, X509Util.toPemCert(certs.get(0)).getBytes(StandardCharsets.UTF_8));
      } else {
        throw new IllegalCmdParamException("invalid outform " + outform);
      }

      return null;
    }

  }

  @Command(scope = "ca", name = "cacerts", description = "get CA's certificate chain")
  @Service
  public static class CaCerts extends CaAction {

    @Argument(name = "name", required = true, description = "CA name")
    @Completion(CaCompleters.CaNameCompleter.class)
    private String name;

    @Option(name = "--out", aliases = "-o", required = true,
        description = "where to save the certificate chain (PEM file)")
    @Completion(FileCompleter.class)
    protected String outFile;

    @Override
    protected Object execute0() throws Exception {
      List certs = caManager.getCaCerts(name);
      IoUtil.save(outFile,
          X509Util.encodeCertificates(certs.toArray(new X509Cert[0])).getBytes(StandardCharsets.UTF_8));
      return null;
    }

  }

  @Command(scope = "ca", name = "ca-info", description = "show information of CA")
  @Service
  public static class CaInfo extends CaAction {

    @Argument(index = 0, name = "name", description = "CA name")
    @Completion(CaCompleters.CaNameCompleter.class)
    private String name;

    @Option(name = "--verbose", aliases = "-v", description = "show CA information verbosely")
    private Boolean verbose = Boolean.FALSE;

    @Override
    protected Object execute0() throws Exception {
      StringBuilder sb = new StringBuilder();
      if (name == null) {
        sb.append("successful CAs:\n");
        String prefix = "  ";
        printCaNames(sb, caManager.getSuccessfulCaNames(), prefix);

        sb.append("failed CAs:\n");
        printCaNames(sb, caManager.getFailedCaNames(), prefix);

        sb.append("inactive CAs:\n");
        printCaNames(sb, caManager.getInactiveCaNames(), prefix);
      } else {
        CaEntry caEntry = Optional.ofNullable(caManager.getCa(name)).orElseThrow(
            () -> new CmdFailure("could not find CA '" + name + "'"));
        if (CaStatus.active == caEntry.getStatus()) {
          boolean started = caManager.getSuccessfulCaNames().contains(caEntry.getIdent().getName());
          sb.append("started:              ").append(started).append("\n");
        }
        Set aliases = caManager.getAliasesForCa(name);
        sb.append("aliases:              ").append(toString(aliases)).append("\n");
        sb.append(caEntry.toString(verbose));

        Set publisherNames = getPublisherNamesForCa(name);
        sb.append("\nAssociated publishers:");
        if (CollectionUtil.isEmpty(publisherNames)) {
          sb.append(" -");
        } else {
          List names = new ArrayList<>(publisherNames);
          Collections.sort(names);
          sb.append(" ").append(names);
        }

        Set profiles = caManager.getCertprofilesForCa(name);
        sb.append("\nAssociated certificate profiles:");
        if (CollectionUtil.isEmpty(profiles)) {
          sb.append(" -");
        } else {
          sb.append(" ").append(profiles).append("");
        }

        Set requestors = caManager.getRequestorsForCa(name);
        sb.append("\nAssociated requestors:");
        if (CollectionUtil.isEmpty(requestors)) {
          sb.append(" -");
        } else {
          for (CaHasRequestorEntry m : requestors) {
            sb.append("\n\t").append(m.getRequestorIdent().getName())
                .append(", permissions=").append(m.getPermissions())
                .append(", profiles=").append(m.getProfiles());
          }
        }
      }

      println(sb.toString());
      return null;
    } // method execute0

  } // class CaInfo

  @Command(scope = "ca", name = "ca-rm", description = "remove CA")
  @Service
  public static class CaRm extends CaAction {

    @Argument(index = 0, name = "name", required = true, description = "CA name")
    @Completion(CaCompleters.CaNameCompleter.class)
    private String name;

    @Option(name = "--force", aliases = "-f", description = "without prompt")
    private Boolean force = Boolean.FALSE;

    @Override
    protected Object execute0() throws Exception {
      String msg = "CA " + name;
      if (force || confirm("Do you want to remove " + msg, 3)) {
        try {
          caManager.removeCa(name);
          println("removed " + msg);
        } catch (CaMgmtException ex) {
          throw new CmdFailure("could not remove " + msg + ", error: " + ex.getMessage(), ex);
        }
      }
      return null;
    } // method execute0

  } // class CaRm

  @Command(scope = "ca", name = "ca-revoke", description = "revoke CA")
  @Service
  public static class CaRevoke extends CaAction {

    public static final List PERMITTED_REASONS = List.of(
        CrlReason.UNSPECIFIED, CrlReason.KEY_COMPROMISE, CrlReason.CA_COMPROMISE,
        CrlReason.AFFILIATION_CHANGED, CrlReason.SUPERSEDED, CrlReason.CESSATION_OF_OPERATION,
        CrlReason.CERTIFICATE_HOLD, CrlReason.PRIVILEGE_WITHDRAWN);

    @Argument(index = 0, name = "name", description = "CA name", required = true)
    @Completion(CaCompleters.CaNameCompleter.class)
    private String caName;

    @Option(name = "--reason", required = true, description = "CRL reason")
    @Completion(CaCompleters.CaCrlReasonCompleter.class)
    private String reason;

    @Option(name = "--rev-date", description = "revocation date, UTC time of format yyyyMMddHHmmss")
    private String revocationDateS;

    @Option(name = "--inv-date", description = "invalidity date, UTC time of format yyyyMMddHHmmss")
    private String invalidityDateS;

    @Override
    protected Object execute0() throws Exception {
      CrlReason crlReason = CrlReason.forNameOrText(reason);

      if (!PERMITTED_REASONS.contains(crlReason)) {
        throw new IllegalCmdParamException("reason " + reason + " is not permitted");
      }

      if (!caManager.getCaNames().contains(caName)) {
        throw new IllegalCmdParamException("invalid CA name " + caName);
      }

      Instant revocationDate = isNotBlank(revocationDateS)
          ? DateUtil.parseUtcTimeyyyyMMddhhmmss(revocationDateS) : Instant.now();

      Instant invalidityDate = null;
      if (isNotBlank(invalidityDateS)) {
        invalidityDate = DateUtil.parseUtcTimeyyyyMMddhhmmss(invalidityDateS);
      }

      try {
        caManager.revokeCa(caName, new CertRevocationInfo(crlReason, revocationDate, invalidityDate));
        println("revoked CA " + caName);
        return null;
      } catch (CaMgmtException ex) {
        throw new CmdFailure("could not revoke CA " + caName + ", error: " + ex.getMessage(), ex);
      }
    } // method execute0

  } // class CaRevoke

  @Command(scope = "ca", name = "ca-unrevoke", description = "unrevoke CA")
  @Service
  public static class CaUnrevoke extends CaAction {

    @Argument(index = 0, name = "name", required = true, description = "CA name")
    @Completion(CaCompleters.CaNameCompleter.class)
    private String caName;

    @Override
    protected Object execute0() throws Exception {
      if (!caManager.getCaNames().contains(caName)) {
        throw new IllegalCmdParamException("invalid CA name " + caName);
      }

      try {
        caManager.unrevokeCa(caName);
        println("unrevoked CA " + caName);
        return null;
      } catch (CaMgmtException ex) {
        throw new CmdFailure("could not unrevoke CA " + caName + ", error: " + ex.getMessage(), ex);
      }
    } // method execute0

  } // class CaUnrevoke

  @Command(scope = "ca", name = "ca-up", description = "update CA")
  @Service
  public static class CaUp extends CaAction {

    @Option(name = "--name", aliases = "-n", required = true, description = "CA name")
    @Completion(CaCompleters.CaNameCompleter.class)
    private String caName;

    @Option(name = "--sn-len", description = "number of octets of the serial number, between "
            + CaManager.MIN_SERIALNUMBER_SIZE + " and " + CaManager.MAX_SERIALNUMBER_SIZE)
    private Integer snLen;

    @Option(name = "--status", description = "CA status")
    @Completion(CaCompleters.CaStatusCompleter.class)
    private String caStatus;

    @Option(name = "--ca-cert-uri", multiValued = true, description = "CA certificate URI")
    private List caCertUris;

    @Option(name = "--ocsp-uri", multiValued = true, description = "OCSP URI or 'null'")
    private List ocspUris;

    @Option(name = "--crl-uri", multiValued = true, description = "CRL distribution point URI or 'null'")
    private List crlUris;

    @Option(name = "--deltacrl-uri", multiValued = true, description = "delta CRL distribution point URI or 'null'")
    private List deltaCrlUris;

    @Option(name = "--permission", multiValued = true, description = "permission")
    @Completion(CaCompleters.PermissionCompleter.class)
    private List permissions;

    @Option(name = "--max-validity", description = "maximal validity")
    private String maxValidity;

    @Option(name = "--expiration-period", description = "days before expiration time of CA to issue certificates")
    private Integer expirationPeriod;

    @Option(name = "--keep-expired-certs", description = "days to keep expired certificates")
    private Integer keepExpiredCertDays;

    @Option(name = "--crl-signer", description = "CRL signer name or 'null'")
    @Completion(CaCompleters.SignerNamePlusNullCompleter.class)
    private String crlSignerName;

    @Option(name = "--keypair-gen", multiValued = true, description = "(ordered) Keypair generation name or 'null")
    @Completion(CaCompleters.KeypairGenNameCompleter.class)
    private List keypairGenNames;

    @Option(name = "--crl-control", description = "CRL control or 'null'")
    private String crlControl;

    @Option(name = "--ctlog-control", description = "CT log control")
    private String ctlogControl;

    @Option(name = "--revoke-suspended-control", description = "Revoke suspended certificates control")
    private String revokeSuspendedControl;

    @Option(name = "--num-crls", description = "number of CRLs to be kept in database")
    private Integer numCrls;

    @Option(name = "--cert", description = "CA certificate file")
    @Completion(FileCompleter.class)
    private String certFile;

    @Option(name = "--certchain", multiValued = true, description = "certificate chain of CA certificate")
    @Completion(FileCompleter.class)
    private List issuerCertFiles;

    @Option(name = "--signer-type", description = "CA signer type")
    @Completion(CaCompleters.SignerTypeCompleter.class)
    private String signerType;

    @Option(name = "--signer-conf", description = "CA signer configuration or 'null'")
    private String signerConf;

    @Option(name = "--save-cert", description = "whether to save the certificate")
    @Completion(Completers.YesNoCompleter.class)
    private String saveCertS;

    @Option(name = "--save-keypair", description = "whether to save the keypair generated by the CA")
    @Completion(Completers.YesNoCompleter.class)
    private String saveKeypairS;

    @Option(name = "--validity-mode", description = "mode of valditity")
    @Completion(CaCompleters.ValidityModeCompleter.class)
    private String validityModeS;

    @Option(name = "--extra-control", description = "extra control")
    private String extraControl;

    protected ChangeCaEntry getChangeCaEntry() throws Exception {
      ChangeCaEntry entry = new ChangeCaEntry(new NameId(null, caName));

      if (snLen != null) {
        Args.range(snLen, "sn-len", CaManager.MIN_SERIALNUMBER_SIZE, CaManager.MAX_SERIALNUMBER_SIZE);
        entry.setSerialNoLen(snLen);
      }

      if (caStatus != null) {
        entry.setStatus(CaStatus.forName(caStatus));
      }

      if (expirationPeriod != null && expirationPeriod < 0) {
        throw new IllegalCmdParamException("invalid expirationPeriod: " + expirationPeriod);
      } else {
        entry.setExpirationPeriod(expirationPeriod);
      }

      if (keepExpiredCertDays != null) {
        entry.setKeepExpiredCertDays(keepExpiredCertDays);
      }

      if (certFile != null) {
        entry.setEncodedCert(IoUtil.read(certFile));
      }

      if (CollectionUtil.isNotEmpty(issuerCertFiles)) {
        List list = new ArrayList<>(issuerCertFiles.size());
        for (String m : issuerCertFiles) {
          if (CaManager.NULL.equalsIgnoreCase(m)) {
            list.clear();
            break;
          }

          list.add(X509Util.parseCert(Paths.get(m).toFile()).getEncoded());
        }
        entry.setEncodedCertchain(list);
      }

      if (signerConf != null) {
        String tmpSignerType = signerType;
        if (tmpSignerType == null) {
          CaEntry caEntry = Optional.ofNullable(caManager.getCa(caName)).orElseThrow(
              () -> new IllegalCmdParamException("please specify the signerType"));
          tmpSignerType = caEntry.getSignerType();
        }

        signerConf = ShellUtil.canonicalizeSignerConf(tmpSignerType, signerConf, securityFactory);
        entry.setSignerConf(signerConf);
      }

      if (saveCertS != null) {
        entry.setSaveCert(isEnabled(saveCertS, true, "save-cert"));
      }

      if (saveKeypairS != null) {
        entry.setSaveKeypair(isEnabled(saveKeypairS, false, "save-keypair"));
      }

      if (CollectionUtil.isNotEmpty(permissions)) {
        entry.setPermission(permissions);
      }

      entry.setCaUris(new CaUris(getUris(caCertUris), getUris(ocspUris), getUris(crlUris), getUris(deltaCrlUris)));

      if (validityModeS != null) {
        entry.setValidityMode(ValidityMode.forName(validityModeS));
      }

      if (maxValidity != null) {
        entry.setMaxValidity(Validity.getInstance(maxValidity));
      }

      if (crlControl != null) {
        entry.setCrlControl(crlControl);
      }

      if (ctlogControl != null) {
        entry.setCtlogControl(ctlogControl);
      }

      if (revokeSuspendedControl != null) {
        entry.setRevokeSuspendedControl(revokeSuspendedControl);
      }

      if (crlSignerName != null) {
        entry.setCrlSignerName(crlSignerName);
      }

      if (CollectionUtil.isNotEmpty(keypairGenNames)) {
        if (CaManager.NULL.equalsIgnoreCase(keypairGenNames.get(0))) {
          keypairGenNames.clear();
        }
        entry.setKeypairGenNames(keypairGenNames);
      }

      if (extraControl != null) {
        entry.setExtraControl(new ConfPairs(extraControl).getEncoded());
      }

      if (numCrls != null) {
        entry.setNumCrls(numCrls);
      }

      return entry;
    } // method getChangeCaEntry

    @Override
    protected Object execute0() throws Exception {
      try {
        caManager.changeCa(getChangeCaEntry());
        println("updated CA " + caName);
        return null;
      } catch (CaMgmtException ex) {
        throw new CmdFailure("could not update CA " + caName + ", error: " + ex.getMessage(), ex);
      }
    } // method execute0

    private static List getUris(List uris) {
      if (uris == null) {
        return null;
      }

      boolean clearUris = false;
      for (String uri : uris) {
        if (CaManager.NULL.equalsIgnoreCase(uri)) {
          clearUris = true;
          break;
        }
      }

      return clearUris ? Collections.emptyList() : new ArrayList<>(uris);
    } // method getUris

  } // class CaUp

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy