[Pki-devel] [PATCH] 0048-0049 Lightweight CAs: implement deletion

Fraser Tweedale ftweedal at redhat.com
Wed Sep 30 14:00:03 UTC 2015


Updated patch attached. Comments inline.

On Wed, Sep 30, 2015 at 06:35:57PM +1000, Fraser Tweedale wrote:
> > 3) It would be good to have a "Are you sure?" dialog on the CLI (with
> > relevant override option).
> > 
> Will do.
> 
Done.

> > 5) I have been thinking about ways to restrict delete.  We should 
> >    discuss and decide on options.  Some ideas:
> > 
> >    a) Add CS.cfg option to disable deletes (for production say).
> >
> Disagree; don't want more config in flat files.  Having the knob in
> the database would be better but I prefer a combination of other
> options (see below).
> 
> >    b) Add optional field (deletable) to the CA entry.  This can be
> >       set by the creating admin to be True for test environments or
> >       cases where we know the environment will be short lived, or
> >       False for long lived CAs.  Default could be configurable.
> > 
> >       CAs could still be deleted, but only by doing something
> >       out-of-band --like modifying the db entry using pki-server
> >       commands or similar.
> >
> >    c) Requiring CAs to be disabled before deleting them.
> >
> I'm in favour of this.
> 
> >    d) Setting a separate ACL for delete, so that it would be easier
> >       for admins to set special permissions for delete.
> >
> And in favour of this.
> 
> >    ... others?
> > 
> I like (c) plus (d) plus perhaps a pkispawn knob that controls
> whether the admin-can-delete ACL gets added at the beginning.
> 
> Let me know what you think and thanks for your feedback!
> 
(c) and (d) are implemented in updated patch.  If you agree with (c)
plus (d) plus pkispawn knob (I guess we'll call that (e)), I'll file
a ticket for (e).

Cheers,
Fraser
-------------- next part --------------
From 285dd4c916f21f59484bec90336acac9170fb51e Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftweedal at redhat.com>
Date: Tue, 29 Sep 2015 11:17:21 -0400
Subject: [PATCH] Lightweight CAs: implement deletion API and CLI

Fixes: https://fedorahosted.org/pki/ticket/1324
---
 base/ca/shared/conf/acl.ldif                       |  1 +
 base/ca/shared/conf/acl.properties                 |  1 +
 .../src/com/netscape/ca/CertificateAuthority.java  | 63 ++++++++++++++++++
 .../dogtagpki/server/ca/rest/AuthorityService.java | 35 ++++++++--
 .../certsrv/authority/AuthorityClient.java         |  5 ++
 .../certsrv/authority/AuthorityResource.java       |  8 +++
 .../netscape/certsrv/ca/CAEnabledException.java    | 15 +++++
 .../netscape/certsrv/ca/ICertificateAuthority.java |  6 ++
 .../netscape/cmstools/authority/AuthorityCLI.java  |  1 +
 .../cmstools/authority/AuthorityRemoveCLI.java     | 74 ++++++++++++++++++++++
 10 files changed, 205 insertions(+), 4 deletions(-)
 create mode 100644 base/common/src/com/netscape/certsrv/ca/CAEnabledException.java
 create mode 100644 base/java-tools/src/com/netscape/cmstools/authority/AuthorityRemoveCLI.java

diff --git a/base/ca/shared/conf/acl.ldif b/base/ca/shared/conf/acl.ldif
index 54c9f1d5c64b6578de83f1b7ffdff922a69975f4..27d89a3131e9220b4c03b17aad14b364fe97ff20 100644
--- a/base/ca/shared/conf/acl.ldif
+++ b/base/ca/shared/conf/acl.ldif
@@ -59,3 +59,4 @@ resourceACLS: certServer.ca.selftests:read,execute:allow (read,execute) group="A
 resourceACLS: certServer.ca.users:execute:allow (execute) group="Administrators":Admins may execute user operations
 resourceACLS: certServer.ca.authorities:list,read:allow (list,read) user="anybody":Anybody may list and read lightweight authorities
 resourceACLS: certServer.ca.authorities:create,modify:allow (create,modify) group="Administrators":Administrators may create and modify lightweight authorities
+resourceACLS: certServer.ca.authorities:delete:allow (delete) group="Administrators":Administrators may delete lightweight authorities
diff --git a/base/ca/shared/conf/acl.properties b/base/ca/shared/conf/acl.properties
index f0b5b9f650ad2fc4bde531ade94347a7280d3089..8b3e9d0eea09e5e3ab8271888ab0532d47b69348 100644
--- a/base/ca/shared/conf/acl.properties
+++ b/base/ca/shared/conf/acl.properties
@@ -25,3 +25,4 @@ authorities.create = certServer.ca.authorities,create
 authorities.list = certServer.ca.authorities,list
 authorities.modify = certServer.ca.authorities,modify
 authorities.read = certServer.ca.authorities,read
+authorities.delete = certServer.ca.authorities,delete
diff --git a/base/ca/src/com/netscape/ca/CertificateAuthority.java b/base/ca/src/com/netscape/ca/CertificateAuthority.java
index b3663ed1d497d03651ad1fa753b4e23ae4aea6b0..af6a2af1109efbdbeeb122cf6e877fc68ee4fd3e 100644
--- a/base/ca/src/com/netscape/ca/CertificateAuthority.java
+++ b/base/ca/src/com/netscape/ca/CertificateAuthority.java
@@ -50,9 +50,11 @@ import org.mozilla.jss.asn1.INTEGER;
 import org.mozilla.jss.asn1.InvalidBERException;
 import org.mozilla.jss.asn1.OBJECT_IDENTIFIER;
 import org.mozilla.jss.asn1.OCTET_STRING;
+import org.mozilla.jss.crypto.CryptoStore;
 import org.mozilla.jss.crypto.CryptoToken;
 import org.mozilla.jss.crypto.KeyPairAlgorithm;
 import org.mozilla.jss.crypto.KeyPairGenerator;
+import org.mozilla.jss.crypto.NoSuchItemOnTokenException;
 import org.mozilla.jss.crypto.SignatureAlgorithm;
 import org.mozilla.jss.crypto.TokenException;
 import org.mozilla.jss.pkix.cert.Extension;
@@ -68,6 +70,7 @@ import com.netscape.certsrv.base.Nonces;
 import com.netscape.certsrv.base.PKIException;
 import com.netscape.certsrv.ca.AuthorityID;
 import com.netscape.certsrv.ca.CADisabledException;
+import com.netscape.certsrv.ca.CAEnabledException;
 import com.netscape.certsrv.ca.CANotFoundException;
 import com.netscape.certsrv.ca.CATypeException;
 import com.netscape.certsrv.ca.ECAException;
@@ -2624,4 +2627,64 @@ public class CertificateAuthority implements ICertificateAuthority, ICertAuthori
         }
     }
 
+    public void deleteAuthority() throws EBaseException {
+        if (isHostAuthority())
+            throw new CATypeException("Cannot delete the host CA");
+
+        if (authorityEnabled)
+            throw new CAEnabledException("Must disable CA before deletion");
+
+        caMap.remove(authorityID);
+        shutdown();
+
+        // delete ldap entry
+        ILdapConnFactory dbFactory = CMS.getLdapBoundConnFactory("updateAuthority");
+        dbFactory.init(CMS.getConfigStore().getSubStore("internaldb"));
+        LDAPConnection conn = dbFactory.getConn();
+        String dn = "cn=" + authorityID.toString() + ",ou=authorities,ou="
+            + getId() + "," + getDBSubsystem().getBaseDN();
+        try {
+            conn.delete(dn);
+        } catch (LDAPException e) {
+            throw new ELdapException("Error deleting authority entry '" + dn + "': " + e);
+        } finally {
+            dbFactory.returnConn(conn);
+            dbFactory.reset();
+        }
+
+        CryptoManager cryptoManager;
+        try {
+            cryptoManager = CryptoManager.getInstance();
+        } catch (CryptoManager.NotInitializedException e) {
+            // can't happen
+            throw new ECAException("CryptoManager not initialized");
+        }
+
+        // delete cert
+        CryptoStore cryptoStore =
+            cryptoManager.getInternalKeyStorageToken().getCryptoStore();
+        try {
+            cryptoStore.deleteCert(mCaX509Cert);
+        } catch (NoSuchItemOnTokenException e) {
+            CMS.debug("deleteCA: cert is not on token: " + e);
+            // if the cert isn't there, never mind
+        } catch (TokenException e) {
+            CMS.debug("deleteCA: TokenExcepetion while deleting cert: " + e);
+            throw new ECAException("TokenException while deleting cert: " + e);
+        }
+
+        // delete key
+        try {
+            cryptoStore.deletePrivateKey(mSigningUnit.getPrivateKey());
+        } catch (NoSuchItemOnTokenException e) {
+            CMS.debug("deleteCA: private key is not on token: " + e);
+            // if the key isn't there, never mind
+        } catch (TokenException e) {
+            CMS.debug("deleteCA: TokenExcepetion while deleting private key: " + e);
+            // TODO don't know what causes this yet, or how to
+            // prevent it.
+            //throw new ECAException("TokenException while deleting private key: " + e);
+        }
+    }
+
 }
diff --git a/base/ca/src/org/dogtagpki/server/ca/rest/AuthorityService.java b/base/ca/src/org/dogtagpki/server/ca/rest/AuthorityService.java
index 820f8ab6499eed9fdb8e3d8d782df64c71ad1fc3..07fa28f53fde37dae46c0e2279af27f88b2616c7 100644
--- a/base/ca/src/org/dogtagpki/server/ca/rest/AuthorityService.java
+++ b/base/ca/src/org/dogtagpki/server/ca/rest/AuthorityService.java
@@ -42,6 +42,7 @@ import com.netscape.certsrv.base.ForbiddenException;
 import com.netscape.certsrv.base.PKIException;
 import com.netscape.certsrv.base.ResourceNotFoundException;
 import com.netscape.certsrv.ca.AuthorityID;
+import com.netscape.certsrv.ca.CAEnabledException;
 import com.netscape.certsrv.ca.CANotFoundException;
 import com.netscape.certsrv.ca.CATypeException;
 import com.netscape.certsrv.ca.ICertificateAuthority;
@@ -99,7 +100,7 @@ public class AuthorityService extends PKIService implements AuthorityResource {
             try {
                 aid = new AuthorityID(aidString);
             } catch (IllegalArgumentException e) {
-                throw new BadRequestException("Bad CA ID: " + aidString);
+                throw new BadRequestException("Bad AuthorityID: " + aidString);
             }
 
             ca = hostCA.getCA(aid);
@@ -116,7 +117,7 @@ public class AuthorityService extends PKIService implements AuthorityResource {
         try {
             aid = new AuthorityID(aidString);
         } catch (IllegalArgumentException e) {
-            throw new BadRequestException("Bad CA ID: " + aidString);
+            throw new BadRequestException("Bad AuthorityID: " + aidString);
         }
 
         ICertificateAuthority ca = hostCA.getCA(aid);
@@ -143,7 +144,7 @@ public class AuthorityService extends PKIService implements AuthorityResource {
         try {
             aid = new AuthorityID(aidString);
         } catch (IllegalArgumentException e) {
-            throw new BadRequestException("Bad CA ID: " + aidString);
+            throw new BadRequestException("Bad AuthorityID: " + aidString);
         }
 
         ICertificateAuthority ca = hostCA.getCA(aid);
@@ -198,7 +199,7 @@ public class AuthorityService extends PKIService implements AuthorityResource {
         try {
             aid = new AuthorityID(aidString);
         } catch (IllegalArgumentException e) {
-            throw new BadRequestException("Bad CA ID: " + aidString);
+            throw new BadRequestException("Bad AuthorityID: " + aidString);
         }
 
         ICertificateAuthority ca = hostCA.getCA(aid);
@@ -232,6 +233,32 @@ public class AuthorityService extends PKIService implements AuthorityResource {
             new AuthorityData(null, null, null, null, false, null));
     }
 
+    @Override
+    public Response deleteCA(String aidString) {
+        AuthorityID aid = null;
+        try {
+            aid = new AuthorityID(aidString);
+        } catch (IllegalArgumentException e) {
+            throw new BadRequestException("Bad AuthorityID: " + aidString);
+        }
+
+        ICertificateAuthority ca = hostCA.getCA(aid);
+        if (ca == null)
+            throw new ResourceNotFoundException("CA \"" + aidString + "\" not found");
+
+        try {
+            ca.deleteAuthority();
+            return createNoContentResponse();
+        } catch (CATypeException e) {
+            throw new ForbiddenException(e.toString());
+        } catch (CAEnabledException e) {
+            throw new ConflictingOperationException(e.toString());
+        } catch (EBaseException e) {
+            CMS.debug(e);
+            throw new PKIException("Error modifying authority: " + e.toString());
+        }
+    }
+
     private static AuthorityData readAuthorityData(ICertificateAuthority ca)
             throws PKIException {
         String dn;
diff --git a/base/common/src/com/netscape/certsrv/authority/AuthorityClient.java b/base/common/src/com/netscape/certsrv/authority/AuthorityClient.java
index 86de3352e2424211125c146edf759481448a2694..5a80877ca4479058ba88005421c46d092b2df6a6 100644
--- a/base/common/src/com/netscape/certsrv/authority/AuthorityClient.java
+++ b/base/common/src/com/netscape/certsrv/authority/AuthorityClient.java
@@ -59,4 +59,9 @@ public class AuthorityClient extends Client {
         return client.getEntity(response, AuthorityData.class);
     }
 
+    public void deleteCA(String aidString) {
+        Response response = proxy.deleteCA(aidString);
+        client.getEntity(response, Void.class);
+    }
+
 }
diff --git a/base/common/src/com/netscape/certsrv/authority/AuthorityResource.java b/base/common/src/com/netscape/certsrv/authority/AuthorityResource.java
index eaef903db444512dbea6c87b11800130d94a944d..c6dc696247122b5f07802696c38c2f3517341106 100644
--- a/base/common/src/com/netscape/certsrv/authority/AuthorityResource.java
+++ b/base/common/src/com/netscape/certsrv/authority/AuthorityResource.java
@@ -1,5 +1,6 @@
 package com.netscape.certsrv.authority;
 
+import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.PUT;
@@ -93,4 +94,11 @@ public interface AuthorityResource {
     @ACLMapping("authorities.modify")
     public Response disableCA(@PathParam("id") String caIDString);
 
+    @DELETE
+    @Path("{id}")
+    @ClientResponseType(entityType=Void.class)
+    @AuthMethodMapping("authorities")
+    @ACLMapping("authorities.delete")
+    public Response deleteCA(@PathParam("id") String caIDString);
+
 }
diff --git a/base/common/src/com/netscape/certsrv/ca/CAEnabledException.java b/base/common/src/com/netscape/certsrv/ca/CAEnabledException.java
new file mode 100644
index 0000000000000000000000000000000000000000..4c85276f3bf71bb640a3468f4ed4be4a6aa0180c
--- /dev/null
+++ b/base/common/src/com/netscape/certsrv/ca/CAEnabledException.java
@@ -0,0 +1,15 @@
+package com.netscape.certsrv.ca;
+
+/**
+ * Exception to throw when an operation cannot be performed because
+ * the CA to which the operation pertains is enabled.
+ */
+public class CAEnabledException extends ECAException {
+
+    private static final long serialVersionUID = 1056602856006912665L;
+
+    public CAEnabledException(String msgFormat) {
+        super(msgFormat);
+    }
+
+}
diff --git a/base/common/src/com/netscape/certsrv/ca/ICertificateAuthority.java b/base/common/src/com/netscape/certsrv/ca/ICertificateAuthority.java
index 31d5c9277a63ca7c916f39651300b0c9a9061c1e..96bc392294f27d57d9795c2b1b793b8cbc001fda 100644
--- a/base/common/src/com/netscape/certsrv/ca/ICertificateAuthority.java
+++ b/base/common/src/com/netscape/certsrv/ca/ICertificateAuthority.java
@@ -583,4 +583,10 @@ public interface ICertificateAuthority extends ISubsystem {
      */
     public void modifyAuthority(Boolean enabled, String desc)
         throws EBaseException;
+
+    /**
+     * Delete this lightweight CA.
+     */
+    public void deleteAuthority()
+        throws EBaseException;
 }
diff --git a/base/java-tools/src/com/netscape/cmstools/authority/AuthorityCLI.java b/base/java-tools/src/com/netscape/cmstools/authority/AuthorityCLI.java
index 99d38ad1b989e171079df78ddd8b2774817ccb33..4fbcfef760086928b2e0e75fe4fc56f1b249b5fd 100644
--- a/base/java-tools/src/com/netscape/cmstools/authority/AuthorityCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/authority/AuthorityCLI.java
@@ -17,6 +17,7 @@ public class AuthorityCLI extends CLI {
         addModule(new AuthorityCreateCLI(this));
         addModule(new AuthorityDisableCLI(this));
         addModule(new AuthorityEnableCLI(this));
+        addModule(new AuthorityRemoveCLI(this));
     }
 
     public String getFullName() {
diff --git a/base/java-tools/src/com/netscape/cmstools/authority/AuthorityRemoveCLI.java b/base/java-tools/src/com/netscape/cmstools/authority/AuthorityRemoveCLI.java
new file mode 100644
index 0000000000000000000000000000000000000000..24918a34510e92ce8a22f4e85e4800a073b4c87c
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/authority/AuthorityRemoveCLI.java
@@ -0,0 +1,74 @@
+package com.netscape.cmstools.authority;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.util.Arrays;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.ParseException;
+
+import com.netscape.certsrv.authority.AuthorityData;
+import com.netscape.certsrv.ca.AuthorityID;
+import com.netscape.cmstools.cli.CLI;
+import com.netscape.cmstools.cli.MainCLI;
+
+public class AuthorityRemoveCLI extends CLI {
+
+    public AuthorityCLI authorityCLI;
+
+    public AuthorityRemoveCLI(AuthorityCLI authorityCLI) {
+        super("del", "Delete Authority", authorityCLI);
+        this.authorityCLI = authorityCLI;
+
+        options.addOption(null, "force", false, "Force delete");
+    }
+
+    public void printHelp() {
+        formatter.printHelp(getFullName() + " <dn>", options);
+    }
+
+    public void execute(String[] args) throws Exception {
+        // Always check for "--help" prior to parsing
+        if (Arrays.asList(args).contains("--help")) {
+            // Display usage
+            printHelp();
+            System.exit(0);
+        }
+
+        CommandLine cmd = null;
+
+        try {
+            cmd = parser.parse(options, args);
+        } catch (ParseException e) {
+            System.err.println("Error: " + e.getMessage());
+            printHelp();
+            System.exit(-1);
+        }
+
+        String[] cmdArgs = cmd.getArgs();
+        if (cmdArgs.length != 1) {
+            if (cmdArgs.length < 1)
+                System.err.println("No ID specified.");
+            else
+                System.err.println("Too many arguments.");
+            printHelp();
+            System.exit(-1);
+        }
+
+        if (!cmd.hasOption("force")) {
+            System.out.print("Are you sure (Y/N)? ");
+            System.out.flush();
+
+            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
+            String line = reader.readLine();
+            if (!line.equalsIgnoreCase("Y")) {
+                System.exit(-1);
+            }
+        }
+
+        String aidString = cmdArgs[0];
+        authorityCLI.authorityClient.deleteCA(aidString);
+        MainCLI.printMessage("Deleted authority \"" + aidString + "\"");
+    }
+
+}
-- 
2.4.3



More information about the Pki-devel mailing list