diff options
author | Endi Sukma Dewata <edewata@redhat.com> | 2013-04-19 11:45:10 -0400 |
---|---|---|
committer | Endi Sukma Dewata <edewata@redhat.com> | 2013-04-22 23:49:46 -0400 |
commit | f3e75c44eacc3f861497a288b2713a26953fb39f (patch) | |
tree | b895d4413af980fe7b75f66f483e2642d23fd1a4 /base | |
parent | 7ea5dc61f082c7372924271fd2a44dfb5345b256 (diff) | |
download | pki-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
Diffstat (limited to 'base')
-rw-r--r-- | base/common/src/com/netscape/certsrv/client/PKIConnection.java | 89 | ||||
-rwxr-xr-x | base/java-tools/pki | 5 | ||||
-rw-r--r-- | base/java-tools/src/com/netscape/cmstools/cli/MainCLI.java | 47 |
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); |