From b2a1177e07d28e5eb9741ea6ed72eb28b5d8c570 Mon Sep 17 00:00:00 2001
From: Matthew Harmsen <mharmsen@redhat.com>
Date: Thu, 24 Jan 2013 18:47:00 -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/ClientConfig.java  | 16 ++++
 .../com/netscape/certsrv/client/PKIConnection.java | 89 +++++++++++++++++++---
 base/deploy/src/scriptlets/configuration.jy        |  1 +
 3 files changed, 96 insertions(+), 10 deletions(-)

diff --git a/base/common/src/com/netscape/certsrv/client/ClientConfig.java b/base/common/src/com/netscape/certsrv/client/ClientConfig.java
index 885b60a..5036f0c 100644
--- a/base/common/src/com/netscape/certsrv/client/ClientConfig.java
+++ b/base/common/src/com/netscape/certsrv/client/ClientConfig.java
@@ -52,6 +52,7 @@ public class ClientConfig {
 
     String certDatabase;
     String certNickname;
+    String isInstanceCreationMode = "false";
     String username;
     String password;
 
@@ -86,6 +87,15 @@ public class ClientConfig {
         this.certNickname = certNickname;
     }
 
+    @XmlElement(defaultValue="false")
+    public String getIsInstanceCreationMode() {
+        return isInstanceCreationMode;
+    }
+
+    public void setIsInstanceCreationMode(String isInstanceCreationMode) {
+        this.isInstanceCreationMode = isInstanceCreationMode;
+    }
+
     @XmlElement(name="Username")
     public String getUsername() {
         return username;
@@ -135,6 +145,11 @@ public class ClientConfig {
                 return false;
         } else if (!certNickname.equals(other.certNickname))
             return false;
+        if (isInstanceCreationMode == null) {
+            if (other.isInstanceCreationMode != null)
+                return false;
+        } else if (!isInstanceCreationMode.equals(other.isInstanceCreationMode))
+            return false;
         if (password == null) {
             if (other.password != null)
                 return false;
@@ -178,6 +193,7 @@ public class ClientConfig {
         before.setServerURI("http://localhost:9180/ca");
         before.setCertDatabase("certs");
         before.setCertNickname("caadmin");
+        before.setIsInstanceCreationMode("false");
         before.setPassword("12345");
 
         String string = before.toString();
diff --git a/base/common/src/com/netscape/certsrv/client/PKIConnection.java b/base/common/src/com/netscape/certsrv/client/PKIConnection.java
index 578e1cf..6351e02 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,101 @@ 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) {
+                    // Ignore the "UNTRUSTED_ISSUER" validity status
+                    // during PKI instance creation since we are
+                    // utilizing an untrusted temporary CA cert.
+                    if (config.getIsInstanceCreationMode().equals("false")) {
+                        // Otherwise, issue a WARNING, but allow this process
+                        // to continue since we haven't installed a trusted CA
+                        // cert for this operation.
+                        System.err.println("WARNING: UNTRUSTED ISSUER encountered on '"+serverCert.getSubjectDN()+"' indicates a non-trusted CA cert");
+                    }
+                } 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");
+                } else if (reason == SSLCertificateApprovalCallback.ValidityStatus.CA_CERT_INVALID) {
+                    // Ignore the "CA_CERT_INVALID" validity status
+                    // during PKI instance creation since we are
+                    // utilizing an untrusted temporary CA cert.
+                    if (config.getIsInstanceCreationMode().equals("false")) {
+                        // Otherwise, set approval false to deny this
+                        // 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!");
+                        approval = false;
+                    }
+                } 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).
+                    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!");
+                    }
+                    approval = false;
                 }
             }
 
-            // For other errors return false.
-
-            return false;
+            return approval;
         }
     }
 
diff --git a/base/deploy/src/scriptlets/configuration.jy b/base/deploy/src/scriptlets/configuration.jy
index 5af3bec..9c48109 100644
--- a/base/deploy/src/scriptlets/configuration.jy
+++ b/base/deploy/src/scriptlets/configuration.jy
@@ -77,6 +77,7 @@ def main(argv):
 
     # Setup connection parameters
     client_config = ClientConfig()
+    client_config.setIsInstanceCreationMode("true")
     client_config.setServerURI(master['pki_jython_base_uri'])
 
     # Establish REST Client
-- 
1.8.1

