From b989d7fe75cfbc7798822b8fe9e21ee45178201e Mon Sep 17 00:00:00 2001
From: Matthew Harmsen <mharmsen@redhat.com>
Date: Sat, 19 Jan 2013 04:50:02 -0800
Subject: [PATCH] Fixed cli 'cert-find' clientAuth FQDN hostname issue

* TRAC Ticket #488 - Dogtag 10: Fix cli 'cert-find' clientAuth issue
---
 .../com/netscape/certsrv/client/PKIConnection.java | 73 +++++++++++++++++++---
 1 file changed, 63 insertions(+), 10 deletions(-)

diff --git a/base/common/src/com/netscape/certsrv/client/PKIConnection.java b/base/common/src/com/netscape/certsrv/client/PKIConnection.java
index 578e1cf..d5825ae 100644
--- a/base/common/src/com/netscape/certsrv/client/PKIConnection.java
+++ b/base/common/src/com/netscape/certsrv/client/PKIConnection.java
@@ -2,6 +2,8 @@ package com.netscape.certsrv.client;
 
 import java.io.File;
 import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.Socket;
@@ -154,34 +156,85 @@ 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
+        //        'org.mozilla.jss.ssl.SSLCertificateApprovalCallback'
+        //        under its nested subclass called 'ValidityStatus'.
+
+        // While all reason values should be unique, this method has been
+        // written to return the name of the first defined reason that is
+        // encountered which contains the requested value, or null if no
+        // reason containing the requested value is encountered.
+        public String displayReason(int reason) {
+            Class<SSLCertificateApprovalCallback.ValidityStatus> c =
+                SSLCertificateApprovalCallback.ValidityStatus.class;
+            for (Field f : c.getDeclaredFields()) {
+                int mod = f.getModifiers();
+                if (Modifier.isStatic(mod) &&
+                    Modifier.isPublic(mod) &&
+                    Modifier.isFinal(mod)) {
+                    try {
+                        int value = f.getInt(null);
+                        if (value == reason) {
+                            return f.getName();
+                        }
+                    } catch (IllegalAccessException e) {
+                        e.printStackTrace();
+                    }
+                }
+            }
+
+            return null;
+        }
 
         // Callback to approve or deny returned SSL server cert.
         // Right now, simply approve the cert.
         public boolean approve(org.mozilla.jss.crypto.X509Certificate serverCert,
                 SSLCertificateApprovalCallback.ValidityStatus status) {
 
+            boolean approval = true;
+            String reasonName = null;
+
             if (verbose) System.out.println("Server certificate: "+serverCert.getSubjectDN());
 
             SSLCertificateApprovalCallback.ValidityItem item;
 
+            // If there are no items in the Enumeration returned by
+            // getReasons(), you can assume that the certificate is
+            // trustworthy, and return true to allow the connection to
+            // continue, or you can continue to make further tests of
+            // your own to determine trustworthiness.
             Enumeration<?> errors = status.getReasons();
             while (errors.hasMoreElements()) {
                 item = (SSLCertificateApprovalCallback.ValidityItem) errors.nextElement();
                 int reason = item.getReason();
 
-                if (reason == SSLCertificateApprovalCallback.ValidityStatus.UNTRUSTED_ISSUER ||
-                        reason == SSLCertificateApprovalCallback.ValidityStatus.BAD_CERT_DOMAIN) {
-
-                    // Allow these two since we haven't installed the CA cert for trust.
-
-                    return true;
-
+                if (reason == SSLCertificateApprovalCallback.ValidityStatus.UNTRUSTED_ISSUER) {
+                    // Allow this since we haven't installed a trusted CA cert.
+                    if (verbose) System.out.println("WARNING: UNTRUSTED ISSUER encountered on '"+serverCert.getSubjectDN()+"' indicates a non-trusted CA cert");
+                    continue;
+                } else if (reason == SSLCertificateApprovalCallback.ValidityStatus.BAD_CERT_DOMAIN) {
+                    // Allow common-name mismatches.
+                    if (verbose) System.out.println("WARNING: BAD_CERT_DOMAIN encountered on '"+serverCert.getSubjectDN()+"' indicates a common-name mismatch");
+                    continue;
+                } else {
+                    // Set approval false to deny this certificate so that
+                    // the connection is terminated (Expect an IOException
+                    // on the outstanding read()/write() on the socket).
+                    if (verbose) {
+                        reasonName = displayReason(reason);
+                        if (reasonName != null ) {
+                            System.out.println("ERROR: "+reasonName+" encountered on '"+serverCert.getSubjectDN()+"' results in a denied SSL server cert!");
+                        } else {
+                            System.out.println("ERROR: Unknown/undefined reason "+reason+" encountered on '"+serverCert.getSubjectDN()+"' results in a denied SSL server cert!");
+                        }
+                    }
+                    approval = false;
                 }
             }
 
-            // For other errors return false.
-
-            return false;
+            return approval;
         }
     }
 
-- 
1.8.1

