summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEndi Sukma Dewata <edewata@redhat.com>2013-04-19 11:45:10 -0400
committerEndi Sukma Dewata <edewata@redhat.com>2013-04-22 23:49:46 -0400
commitf3e75c44eacc3f861497a288b2713a26953fb39f (patch)
treeb895d4413af980fe7b75f66f483e2642d23fd1a4
parent7ea5dc61f082c7372924271fd2a44dfb5345b256 (diff)
downloadpki-f3e75c44eacc3f861497a288b2713a26953fb39f.tar.gz
pki-f3e75c44eacc3f861497a288b2713a26953fb39f.tar.xz
pki-f3e75c44eacc3f861497a288b2713a26953fb39f.zip
Added options to reject/ignore cert validity statuses.
New options have been added to the CLI to reject or ignore certain cert validity statuses such as UNTRUSTED_ISSUER or BAD_CERT_DOMAIN. The options can also be defined in pki.conf as a system-wide policy. Ticket #491
-rw-r--r--base/common/src/com/netscape/certsrv/client/PKIConnection.java89
-rwxr-xr-xbase/java-tools/pki5
-rw-r--r--base/java-tools/src/com/netscape/cmstools/cli/MainCLI.java47
3 files changed, 124 insertions, 17 deletions
diff --git a/base/common/src/com/netscape/certsrv/client/PKIConnection.java b/base/common/src/com/netscape/certsrv/client/PKIConnection.java
index 4eba7231a..556779ec8 100644
--- a/base/common/src/com/netscape/certsrv/client/PKIConnection.java
+++ b/base/common/src/com/netscape/certsrv/client/PKIConnection.java
@@ -17,7 +17,9 @@ import java.net.URISyntaxException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Enumeration;
+import java.util.HashSet;
import java.util.List;
import javax.ws.rs.core.MediaType;
@@ -46,6 +48,7 @@ import org.apache.http.conn.scheme.SchemeSocketFactory;
import org.apache.http.entity.BufferedHttpEntity;
import org.apache.http.impl.client.ClientParamsStack;
import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.DefaultRedirectStrategy;
import org.apache.http.impl.client.EntityEnclosingRequestWrapper;
import org.apache.http.impl.client.RequestWrapper;
@@ -78,6 +81,12 @@ public class PKIConnection {
ClientConfig config;
+ Collection<Integer> rejectedCertStatuses;
+ Collection<Integer> ignoredCertStatuses;
+
+ // List to prevent displaying the same warnings/errors again.
+ Collection<Integer> statuses = new HashSet<Integer>();
+
DefaultHttpClient httpClient = new DefaultHttpClient();
ResteasyProviderFactory providerFactory;
@@ -97,6 +106,9 @@ public class PKIConnection {
Scheme scheme = new Scheme("https", 443, new JSSProtocolSocketFactory());
httpClient.getConnectionManager().getSchemeRegistry().register(scheme);
+ // Don't retry operations.
+ httpClient.setHttpRequestRetryHandler(new DefaultHttpRequestRetryHandler(0, false));
+
if (config.getUsername() != null && config.getPassword() != null) {
List<String> authPref = new ArrayList<String>();
authPref.add(AuthPolicy.BASIC);
@@ -264,6 +276,7 @@ public class PKIConnection {
}
private class ServerCertApprovalCB implements SSLCertificateApprovalCallback {
+
// NOTE: The following helper method defined as
// 'public String displayReason(int reason)'
// should be moved into the JSS class called
@@ -296,11 +309,33 @@ public class PKIConnection {
return null;
}
+ public String getMessage(X509Certificate serverCert, int reason) {
+
+ if (reason == SSLCertificateApprovalCallback.ValidityStatus.BAD_CERT_DOMAIN) {
+
+ return "BAD_CERT_DOMAIN encountered on '"+serverCert.getSubjectDN()+"' indicates a common-name mismatch";
+ }
+
+ if (reason == SSLCertificateApprovalCallback.ValidityStatus.UNTRUSTED_ISSUER) {
+ return "UNTRUSTED ISSUER encountered on '" +
+ serverCert.getSubjectDN() + "' indicates a non-trusted CA cert '" +
+ serverCert.getIssuerDN() + "'";
+ }
+
+ if (reason == SSLCertificateApprovalCallback.ValidityStatus.CA_CERT_INVALID) {
+ return "CA_CERT_INVALID encountered on '"+serverCert.getSubjectDN()+"' results in a denied SSL server cert!";
+ }
+
+ String reasonName = displayReason(reason);
+ if (reasonName != null) {
+ return reasonName+" encountered on '"+serverCert.getSubjectDN()+"' results in a denied SSL server cert!";
+ }
+
+ return "Unknown/undefined reason "+reason+" encountered on '"+serverCert.getSubjectDN()+"' results in a denied SSL server cert!";
+ }
+
public boolean handleUntrustedIssuer(X509Certificate serverCert) {
try {
- System.err.println("WARNING: UNTRUSTED ISSUER encountered on '" +
- serverCert.getSubjectDN() + "' indicates a non-trusted CA cert '" +
- serverCert.getIssuerDN() + "'");
System.out.print("Import CA certificate (Y/n)? ");
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
@@ -359,7 +394,6 @@ public class PKIConnection {
SSLCertificateApprovalCallback.ValidityStatus status) {
boolean approval = true;
- String reasonName = null;
if (verbose) System.out.println("Server certificate: "+serverCert.getSubjectDN());
@@ -375,7 +409,15 @@ public class PKIConnection {
item = (SSLCertificateApprovalCallback.ValidityItem) errors.nextElement();
int reason = item.getReason();
- if (reason == SSLCertificateApprovalCallback.ValidityStatus.UNTRUSTED_ISSUER) {
+ if (isRejected(reason)) {
+ if (!statuses.contains(reason))
+ System.err.println("ERROR: " + getMessage(serverCert, reason));
+ approval = false;
+
+ } else if (isIgnored(reason)) {
+ // Ignore validity status
+
+ } else if (reason == SSLCertificateApprovalCallback.ValidityStatus.UNTRUSTED_ISSUER) {
// Ignore the "UNTRUSTED_ISSUER" validity status
// during PKI instance creation since we are
// utilizing an untrusted temporary CA cert.
@@ -383,13 +425,17 @@ public class PKIConnection {
// Otherwise, issue a WARNING, but allow this process
// to continue since we haven't installed a trusted CA
// cert for this operation.
- handleUntrustedIssuer(serverCert);
+ if (!statuses.contains(reason)) {
+ System.err.println("WARNING: " + getMessage(serverCert, reason));
+ handleUntrustedIssuer(serverCert);
+ }
}
} else if (reason == SSLCertificateApprovalCallback.ValidityStatus.BAD_CERT_DOMAIN) {
// Issue a WARNING, but allow this process to continue on
// common-name mismatches.
- System.err.println("WARNING: BAD_CERT_DOMAIN encountered on '"+serverCert.getSubjectDN()+"' indicates a common-name mismatch");
+ if (!statuses.contains(reason))
+ System.err.println("WARNING: " + getMessage(serverCert, reason));
} else if (reason == SSLCertificateApprovalCallback.ValidityStatus.CA_CERT_INVALID) {
// Ignore the "CA_CERT_INVALID" validity status
@@ -400,7 +446,8 @@ public class PKIConnection {
// certificate so that the connection is terminated.
// (Expect an IOException on the outstanding
// read()/write() on the socket).
- System.err.println("ERROR: CA_CERT_INVALID encountered on '"+serverCert.getSubjectDN()+"' results in a denied SSL server cert!");
+ if (!statuses.contains(reason))
+ System.err.println("ERROR: " + getMessage(serverCert, reason));
approval = false;
}
@@ -408,14 +455,12 @@ public class PKIConnection {
// Set approval false to deny this certificate so that
// the connection is terminated. (Expect an IOException
// on the outstanding read()/write() on the socket).
- reasonName = displayReason(reason);
- if (reasonName != null ) {
- System.err.println("ERROR: "+reasonName+" encountered on '"+serverCert.getSubjectDN()+"' results in a denied SSL server cert!");
- } else {
- System.err.println("ERROR: Unknown/undefined reason "+reason+" encountered on '"+serverCert.getSubjectDN()+"' results in a denied SSL server cert!");
- }
+ if (!statuses.contains(reason))
+ System.err.println("ERROR: " + getMessage(serverCert, reason));
approval = false;
}
+
+ statuses.add(reason);
}
return approval;
@@ -540,6 +585,22 @@ public class PKIConnection {
return request.post(String.class);
}
+ public void setRejectedCertStatuses(Collection<Integer> rejectedCertStatuses) {
+ this.rejectedCertStatuses = rejectedCertStatuses;
+ }
+
+ public boolean isRejected(Integer certStatus) {
+ return this.rejectedCertStatuses != null && this.rejectedCertStatuses.contains(certStatus);
+ }
+
+ public void setIgnoredCertStatuses(Collection<Integer> ignoredCertStatuses) {
+ this.ignoredCertStatuses = ignoredCertStatuses;
+ }
+
+ public boolean isIgnored(Integer certStatus) {
+ return this.ignoredCertStatuses != null && this.ignoredCertStatuses.contains(certStatus);
+ }
+
public File getOutput() {
return output;
}
diff --git a/base/java-tools/pki b/base/java-tools/pki
index 197fa6100..07eb4ee28 100755
--- a/base/java-tools/pki
+++ b/base/java-tools/pki
@@ -107,12 +107,15 @@ if( $ARCHITECTURE eq "x86_64" ) {
## based upon the preset LD_LIBRARY_PATH and CP environment variables. ##
###############################################################################
+my $PKI_CLI_OPTIONS = `source /etc/pki/pki.conf && echo \$PKI_CLI_OPTIONS`;
+chomp($PKI_CLI_OPTIONS);
+
my @args = ();
foreach (@ARGV) {
push(@args, quotemeta($_));
}
-my $command = "java -cp $ENV{CLASSPATH} com.netscape.cmstools.cli.MainCLI @args";
+my $command = "java -cp $ENV{CLASSPATH} com.netscape.cmstools.cli.MainCLI $PKI_CLI_OPTIONS @args";
system($command) and do {
exit $? >> 8;
diff --git a/base/java-tools/src/com/netscape/cmstools/cli/MainCLI.java b/base/java-tools/src/com/netscape/cmstools/cli/MainCLI.java
index c6daa7d29..aa4327fe6 100644
--- a/base/java-tools/src/com/netscape/cmstools/cli/MainCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/cli/MainCLI.java
@@ -19,9 +19,11 @@
package com.netscape.cmstools.cli;
import java.io.File;
+import java.lang.reflect.Field;
import java.net.InetAddress;
-import java.net.URISyntaxException;
import java.net.UnknownHostException;
+import java.util.Collection;
+import java.util.HashSet;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
@@ -29,6 +31,7 @@ import org.apache.commons.cli.Options;
import org.apache.commons.lang.StringUtils;
import org.mozilla.jss.CryptoManager;
import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.ssl.SSLCertificateApprovalCallback;
import org.mozilla.jss.util.IncorrectPasswordException;
import org.mozilla.jss.util.Password;
@@ -49,6 +52,9 @@ public class MainCLI extends CLI {
public ClientConfig config = new ClientConfig();
+ public Collection<Integer> rejectedCertStatuses;
+ public Collection<Integer> ignoredCertStatuses;
+
public PKIConnection connection;
public AccountClient accountClient;
@@ -140,12 +146,20 @@ public class MainCLI extends CLI {
option.setArgName("folder");
options.addOption(option);
+ option = new Option(null, "reject-cert-status", true, "Comma-separated list of rejected certificate validity statuses");
+ option.setArgName("list");
+ options.addOption(option);
+
+ option = new Option(null, "ignore-cert-status", true, "Comma-separated list of ignored certificate validity statuses");
+ option.setArgName("list");
+ options.addOption(option);
+
options.addOption("v", false, "Verbose");
options.addOption(null, "help", false, "Help");
options.addOption(null, "version", false, "Version");
}
- public void parseOptions(CommandLine cmd) throws URISyntaxException, UnknownHostException {
+ public void parseOptions(CommandLine cmd) throws Exception {
verbose = cmd.hasOption("v");
output = cmd.getOptionValue("output");
@@ -179,11 +193,40 @@ public class MainCLI extends CLI {
if (password != null)
config.setPassword(password);
+
+ String list = cmd.getOptionValue("reject-cert-status");
+ rejectedCertStatuses = convertCertStatusList(list);
+
+ list = cmd.getOptionValue("ignore-cert-status");
+ ignoredCertStatuses = convertCertStatusList(list);
+ }
+
+ public Collection<Integer> convertCertStatusList(String list) throws Exception {
+
+ if (list == null) return null;
+
+ Collection<Integer> statuses = new HashSet<Integer>();
+
+ Class<SSLCertificateApprovalCallback.ValidityStatus> clazz = SSLCertificateApprovalCallback.ValidityStatus.class;
+
+ for (String status : list.split(",")) {
+ try {
+ Field field = clazz.getField(status);
+ statuses.add(field.getInt(null));
+
+ } catch (NoSuchFieldException e) {
+ throw new Error("Invalid cert status \"" + status + "\".", e);
+ }
+ }
+
+ return statuses;
}
public void connect() throws Exception {
connection = new PKIConnection(config);
connection.setVerbose(verbose);
+ connection.setRejectedCertStatuses(rejectedCertStatuses);
+ connection.setIgnoredCertStatuses(ignoredCertStatuses);
if (output != null) {
File file = new File(output);