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

Fraser Tweedale ftweedal at redhat.com
Tue Sep 29 15:25:33 UTC 2015


The attached patches fix some incorrect synchronization of the
lightweight CAs index (patch 0048) and implement deletion of
lightweight CAs (patch 0049).

These patches replace earlier patches 0048 and 0049 which I rescind.

There is a commented out throw in
CertificateAuthority.deleteAuthority(); I don't yet understand what
causes this failure case but a) everything seems to work (at least
with the small numbers of lightweight CAs I've tested with) and b)
I'm seeking clarification from NSS experts on the matter, so stay
tuned.

Cheers,
Fraser
-------------- next part --------------
From cc19c2e76db61475981c9bf5e860bca9b998c338 Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftweedal at redhat.com>
Date: Tue, 29 Sep 2015 05:59:38 -0400
Subject: [PATCH 48/49] Lightweight CAs: fix caMap synchronization

Some access to caMap was not correctly synchronized, with
authorities (of which there could be many) acquiring their own
intrinsic lock rather than the shared caMap.

Use 'Collections.synchronizedSortedMap' to fix this.  As a bonus,
locking is now more fine-grained.
---
 base/ca/src/com/netscape/ca/CertificateAuthority.java | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/base/ca/src/com/netscape/ca/CertificateAuthority.java b/base/ca/src/com/netscape/ca/CertificateAuthority.java
index 42a0ec4d1d362c9b615cb9483530590e2b785a42..b3663ed1d497d03651ad1fa753b4e23ae4aea6b0 100644
--- a/base/ca/src/com/netscape/ca/CertificateAuthority.java
+++ b/base/ca/src/com/netscape/ca/CertificateAuthority.java
@@ -161,7 +161,8 @@ public class CertificateAuthority implements ICertificateAuthority, ICertAuthori
 
     public final static OBJECT_IDENTIFIER OCSP_NONCE = new OBJECT_IDENTIFIER("1.3.6.1.5.5.7.48.1.2");
 
-    private static final Map<AuthorityID, ICertificateAuthority> caMap = new TreeMap<>();
+    private static final Map<AuthorityID, ICertificateAuthority> caMap =
+        Collections.synchronizedSortedMap(new TreeMap<>());
     protected CertificateAuthority hostCA = null;
     protected AuthorityID authorityID = null;
     protected AuthorityID authorityParentID = null;
@@ -1934,7 +1935,7 @@ public class CertificateAuthority implements ICertificateAuthority, ICertAuthori
      *
      * This method must only be called by the host CA.
      */
-    private synchronized void loadLightweightCAs() throws EBaseException {
+    private void loadLightweightCAs() throws EBaseException {
         ILdapConnFactory dbFactory = CMS.getLdapBoundConnFactory("loadLightweightCAs");
         dbFactory.init(CMS.getConfigStore().getSubStore("internaldb"));
         LDAPConnection conn = dbFactory.getConn();
@@ -2321,10 +2322,12 @@ public class CertificateAuthority implements ICertificateAuthority, ICertAuthori
     /**
      * Enumerate all authorities (including host authority)
      */
-    public synchronized List<ICertificateAuthority> getCAs() {
+    public List<ICertificateAuthority> getCAs() {
         List<ICertificateAuthority> cas = new ArrayList<>();
-        for (ICertificateAuthority ca : caMap.values()) {
-            cas.add(ca);
+        synchronized (caMap) {
+            for (ICertificateAuthority ca : caMap.values()) {
+                cas.add(ca);
+            }
         }
         return cas;
     }
@@ -2379,9 +2382,7 @@ public class CertificateAuthority implements ICertificateAuthority, ICertAuthori
 
         ICertificateAuthority ca = parentCA.createSubCA(
                 subjectDN, description);
-        synchronized (this) {
-            caMap.put(ca.getAuthorityID(), ca);
-        }
+        caMap.put(ca.getAuthorityID(), ca);
         return ca;
     }
 
-- 
2.4.3

-------------- next part --------------
From c922474f0968d71ec903873ced8e4dc6799a6a22 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 49/49] Lightweight CAs: implement deletion API and CLI

Fixes: https://fedorahosted.org/pki/ticket/1324
---
 base/ca/shared/conf/acl.ldif                       |  2 +-
 base/ca/shared/conf/acl.properties                 |  1 +
 .../src/com/netscape/ca/CertificateAuthority.java  | 59 ++++++++++++++++++++++
 .../dogtagpki/server/ca/rest/AuthorityService.java | 32 ++++++++++--
 .../certsrv/authority/AuthorityClient.java         |  5 ++
 .../certsrv/authority/AuthorityResource.java       |  8 +++
 .../netscape/certsrv/ca/ICertificateAuthority.java |  6 +++
 .../netscape/cmstools/authority/AuthorityCLI.java  |  1 +
 .../cmstools/authority/AuthorityRemoveCLI.java     | 59 ++++++++++++++++++++++
 9 files changed, 168 insertions(+), 5 deletions(-)
 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..97c122b2f4575df14e61013a34ddd25adfca30b7 100644
--- a/base/ca/shared/conf/acl.ldif
+++ b/base/ca/shared/conf/acl.ldif
@@ -58,4 +58,4 @@ resourceACLS: certServer.ca.groups:execute:allow (execute) group="Administrators
 resourceACLS: certServer.ca.selftests:read,execute:allow (read,execute) group="Administrators":Only admins can access selftests.
 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:create,modify,delete:allow (create,modify,delete) group="Administrators":Administrators may create, modify and 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..525b9bd8c0dc45a1ad0419ab35f702c57a9e8bfc 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;
@@ -2624,4 +2626,61 @@ public class CertificateAuthority implements ICertificateAuthority, ICertAuthori
         }
     }
 
+    public void deleteAuthority() throws EBaseException {
+        if (isHostAuthority())
+            throw new CATypeException("Cannot delete the host CA");
+
+        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..1449a1e6a58946f1ce1fd6a2d5b5cb7b6b15f7dd 100644
--- a/base/ca/src/org/dogtagpki/server/ca/rest/AuthorityService.java
+++ b/base/ca/src/org/dogtagpki/server/ca/rest/AuthorityService.java
@@ -99,7 +99,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 +116,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 +143,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 +198,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 +232,30 @@ 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 (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/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..8cfb2f84067b63652687feb2c51d29e91baf861f
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/authority/AuthorityRemoveCLI.java
@@ -0,0 +1,59 @@
+package com.netscape.cmstools.authority;
+
+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;
+    }
+
+    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);
+        }
+
+        String aidString = cmdArgs[0];
+        authorityCLI.authorityClient.deleteCA(aidString);
+        MainCLI.printMessage("Deleted authority \"" + aidString + "\"");
+    }
+
+}
-- 
2.4.3



More information about the Pki-devel mailing list