summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFraser Tweedale <ftweedal@redhat.com>2015-09-29 11:17:21 -0400
committerFraser Tweedale <ftweedal@redhat.com>2015-10-06 09:41:38 +1000
commit9a2f79f9fb4dce130d1495450e7a680e04648626 (patch)
tree2932e430e402f3993d5282ae003e9cc1b31af9fc
parentdec7fe7aea653d1192bab47a503c98970f8d898f (diff)
downloadpki-9a2f79f9fb4dce130d1495450e7a680e04648626.tar.gz
pki-9a2f79f9fb4dce130d1495450e7a680e04648626.tar.xz
pki-9a2f79f9fb4dce130d1495450e7a680e04648626.zip
Lightweight CAs: implement deletion API and CLI
Implement lightweight authority deletion including CLI command. To be deleted an authority must be disabled and have no sub-CAs. Fixes: https://fedorahosted.org/pki/ticket/1324
-rw-r--r--base/ca/shared/conf/acl.ldif1
-rw-r--r--base/ca/shared/conf/acl.properties1
-rw-r--r--base/ca/src/com/netscape/ca/CertificateAuthority.java75
-rw-r--r--base/ca/src/org/dogtagpki/server/ca/rest/AuthorityService.java36
-rw-r--r--base/common/src/com/netscape/certsrv/authority/AuthorityClient.java5
-rw-r--r--base/common/src/com/netscape/certsrv/authority/AuthorityResource.java8
-rw-r--r--base/common/src/com/netscape/certsrv/ca/AuthorityID.java4
-rw-r--r--base/common/src/com/netscape/certsrv/ca/CAEnabledException.java15
-rw-r--r--base/common/src/com/netscape/certsrv/ca/CANotLeafException.java16
-rw-r--r--base/common/src/com/netscape/certsrv/ca/ICertificateAuthority.java6
-rw-r--r--base/java-tools/src/com/netscape/cmstools/authority/AuthorityCLI.java1
-rw-r--r--base/java-tools/src/com/netscape/cmstools/authority/AuthorityRemoveCLI.java72
12 files changed, 236 insertions, 4 deletions
diff --git a/base/ca/shared/conf/acl.ldif b/base/ca/shared/conf/acl.ldif
index 54c9f1d5c..27d89a313 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 f0b5b9f65..8b3e9d0ee 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 af4afbdef..449da301f 100644
--- a/base/ca/src/com/netscape/ca/CertificateAuthority.java
+++ b/base/ca/src/com/netscape/ca/CertificateAuthority.java
@@ -72,9 +72,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;
@@ -90,7 +92,9 @@ 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.CANotLeafException;
import com.netscape.certsrv.ca.CATypeException;
import com.netscape.certsrv.ca.ECAException;
import com.netscape.certsrv.ca.ICRLIssuingPoint;
@@ -2624,4 +2628,75 @@ 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");
+
+ boolean hasSubCAs = false;
+ for (ICertificateAuthority ca : getCAs()) {
+ AuthorityID parentAID = ca.getAuthorityParentID();
+ if (parentAID != null && parentAID.equals(this.authorityID)) {
+ hasSubCAs = true;
+ break;
+ }
+ }
+ if (hasSubCAs)
+ throw new CANotLeafException("CA with sub-CAs cannot be deleted (delete sub-CAs first)");
+
+ 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("deleteAuthority: cert is not on token: " + e);
+ // if the cert isn't there, never mind
+ } catch (TokenException e) {
+ CMS.debug("deleteAuthority: 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("deleteAuthority: private key is not on token: " + e);
+ // if the key isn't there, never mind
+ } catch (TokenException e) {
+ CMS.debug("deleteAuthority: 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 820f8ab64..b23a4b853 100644
--- a/base/ca/src/org/dogtagpki/server/ca/rest/AuthorityService.java
+++ b/base/ca/src/org/dogtagpki/server/ca/rest/AuthorityService.java
@@ -42,7 +42,9 @@ 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.CANotLeafException;
import com.netscape.certsrv.ca.CATypeException;
import com.netscape.certsrv.ca.ICertificateAuthority;
import com.netscape.certsrv.ca.IssuerUnavailableException;
@@ -99,7 +101,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 +118,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 +145,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 +200,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 +234,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 | CANotLeafException 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 86de3352e..5a80877ca 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 eaef903db..c6dc69624 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/AuthorityID.java b/base/common/src/com/netscape/certsrv/ca/AuthorityID.java
index daac587b7..9816f87ad 100644
--- a/base/common/src/com/netscape/certsrv/ca/AuthorityID.java
+++ b/base/common/src/com/netscape/certsrv/ca/AuthorityID.java
@@ -29,6 +29,10 @@ public class AuthorityID implements Comparable<AuthorityID> {
return uuid.toString();
}
+ public boolean equals(AuthorityID aid) {
+ return this.compareTo(aid) == 0;
+ }
+
public int compareTo(AuthorityID aid) {
return uuid.compareTo(aid.uuid);
}
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 000000000..4c85276f3
--- /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/CANotLeafException.java b/base/common/src/com/netscape/certsrv/ca/CANotLeafException.java
new file mode 100644
index 000000000..eabca7364
--- /dev/null
+++ b/base/common/src/com/netscape/certsrv/ca/CANotLeafException.java
@@ -0,0 +1,16 @@
+package com.netscape.certsrv.ca;
+
+/**
+ * Exception to throw when an operation cannot be performed because
+ * the CA to which the operation pertains is not a leaf CA (ie, has
+ * sub-CAs).
+ */
+public class CANotLeafException extends ECAException {
+
+ private static final long serialVersionUID = -2729093578678941399L;
+
+ public CANotLeafException(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 31d5c9277..96bc39229 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 99d38ad1b..4fbcfef76 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 000000000..42265b180
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/authority/AuthorityRemoveCLI.java
@@ -0,0 +1,72 @@
+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.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 + "\"");
+ }
+
+}