>From d607ba3fe642b33dd0a12ae3321622898f247f5d Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata@redhat.com>
Date: Mon, 1 Aug 2016 22:35:32 +0200
Subject: [PATCH] Added log messages for certificate validation.

The ConfigCertApprovalCallback has been modified such that it
logs the server certificate being validated and can be configured
to ignore certain validation errors.

The ConfigurationUtils has been modified to use the
ConfigCertApprovalCallback to show and validate the server
certificate in all GET and POST operations except for the
importCertChain() in which the code needs to ignore untrusted
issuer in order to get the certificate chain via SSL.

https://fedorahosted.org/pki/ticket/2424
---
 .../csadmin/ConfigCertApprovalCallback.java        | 63 +++++++++++++++++++++-
 .../cms/servlet/csadmin/ConfigurationUtils.java    | 63 ++++++++++++----------
 2 files changed, 97 insertions(+), 29 deletions(-)

diff --git a/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigCertApprovalCallback.java b/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigCertApprovalCallback.java
index 956c285b5e329d33af0d4f5a4211f6719767de8f..9b741af020c22c54ac9f61fc2103a2856d026fc8 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigCertApprovalCallback.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigCertApprovalCallback.java
@@ -17,17 +17,78 @@
 // --- END COPYRIGHT BLOCK ---
 package com.netscape.cms.servlet.csadmin;
 
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+
 import org.mozilla.jss.crypto.X509Certificate;
 import org.mozilla.jss.ssl.SSLCertificateApprovalCallback;
 
+import com.netscape.certsrv.apps.CMS;
+
 public class ConfigCertApprovalCallback
         implements SSLCertificateApprovalCallback {
 
+    public Set<Integer> ignoredErrors = new HashSet<Integer>();
+
     public ConfigCertApprovalCallback() {
     }
 
+    public void ignoreError(int error) {
+        ignoredErrors.add(error);
+    }
+
+    public String getErrorDescription(int reason) {
+
+        // iterate through all constants in ValidityStatus
+        for (Field f : ValidityStatus.class.getDeclaredFields()) {
+            int mod = f.getModifiers();
+            if (Modifier.isPublic(mod) &&
+                Modifier.isFinal(mod) &&
+                Modifier.isStatic(mod)) {
+
+                try {
+                    int value = f.getInt(null);
+
+                    // if value matches the reason, return the name
+                    if (value == reason) {
+                        return f.getName();
+                    }
+
+                } catch (IllegalAccessException e) {
+                    return "ERROR #" + reason;
+                }
+            }
+        }
+
+        return "UNKNOWN_ERROR";
+    }
+
     public boolean approve(X509Certificate cert,
             SSLCertificateApprovalCallback.ValidityStatus status) {
-        return true;
+
+        CMS.debug("Server certificate:");
+        CMS.debug(" - subject: " + cert.getSubjectDN());
+        CMS.debug(" - issuer: " + cert.getIssuerDN());
+
+        Enumeration<?> errors = status.getReasons();
+        boolean result = true;
+
+        while (errors.hasMoreElements()) {
+            SSLCertificateApprovalCallback.ValidityItem item = (SSLCertificateApprovalCallback.ValidityItem) errors.nextElement();
+            int reason = item.getReason();
+            String description = getErrorDescription(reason);
+
+            if (ignoredErrors.contains(reason)) {
+                CMS.debug("WARNING: " + description);
+            } else {
+                CMS.debug("ERROR: " + description);
+                result = false;
+            }
+        }
+
+        return result;
     }
 }
diff --git a/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java b/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
index ab5e4d63da1d91718ed3795c5fa144d18b5f5a99..fe65bb855a24702c2248d03059716d4246d70d0a 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
@@ -58,34 +58,6 @@ import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response;
 import javax.xml.parsers.ParserConfigurationException;
 
-import netscape.ldap.LDAPAttribute;
-import netscape.ldap.LDAPAttributeSet;
-import netscape.ldap.LDAPConnection;
-import netscape.ldap.LDAPDN;
-import netscape.ldap.LDAPEntry;
-import netscape.ldap.LDAPException;
-import netscape.ldap.LDAPModification;
-import netscape.ldap.LDAPSearchConstraints;
-import netscape.ldap.LDAPSearchResults;
-import netscape.ldap.LDAPv3;
-import netscape.security.pkcs.ContentInfo;
-import netscape.security.pkcs.PKCS10;
-import netscape.security.pkcs.PKCS12;
-import netscape.security.pkcs.PKCS12Util;
-import netscape.security.pkcs.PKCS7;
-import netscape.security.pkcs.SignerInfo;
-import netscape.security.util.DerOutputStream;
-import netscape.security.util.ObjectIdentifier;
-import netscape.security.x509.AlgorithmId;
-import netscape.security.x509.BasicConstraintsExtension;
-import netscape.security.x509.CertificateChain;
-import netscape.security.x509.Extension;
-import netscape.security.x509.Extensions;
-import netscape.security.x509.KeyUsageExtension;
-import netscape.security.x509.X500Name;
-import netscape.security.x509.X509CertImpl;
-import netscape.security.x509.X509Key;
-
 import org.apache.commons.lang.StringUtils;
 import org.apache.velocity.context.Context;
 import org.mozilla.jss.CryptoManager;
@@ -131,6 +103,7 @@ import org.mozilla.jss.pkix.primitive.Attribute;
 import org.mozilla.jss.pkix.primitive.EncryptedPrivateKeyInfo;
 import org.mozilla.jss.pkix.primitive.PrivateKeyInfo;
 import org.mozilla.jss.ssl.SSLCertificateApprovalCallback;
+import org.mozilla.jss.ssl.SSLCertificateApprovalCallback.ValidityStatus;
 import org.mozilla.jss.util.IncorrectPasswordException;
 import org.mozilla.jss.util.Password;
 import org.w3c.dom.Document;
@@ -180,6 +153,34 @@ import com.netscape.cmsutil.ldap.LDAPUtil;
 import com.netscape.cmsutil.util.Utils;
 import com.netscape.cmsutil.xml.XMLObject;
 
+import netscape.ldap.LDAPAttribute;
+import netscape.ldap.LDAPAttributeSet;
+import netscape.ldap.LDAPConnection;
+import netscape.ldap.LDAPDN;
+import netscape.ldap.LDAPEntry;
+import netscape.ldap.LDAPException;
+import netscape.ldap.LDAPModification;
+import netscape.ldap.LDAPSearchConstraints;
+import netscape.ldap.LDAPSearchResults;
+import netscape.ldap.LDAPv3;
+import netscape.security.pkcs.ContentInfo;
+import netscape.security.pkcs.PKCS10;
+import netscape.security.pkcs.PKCS12;
+import netscape.security.pkcs.PKCS12Util;
+import netscape.security.pkcs.PKCS7;
+import netscape.security.pkcs.SignerInfo;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.ObjectIdentifier;
+import netscape.security.x509.AlgorithmId;
+import netscape.security.x509.BasicConstraintsExtension;
+import netscape.security.x509.CertificateChain;
+import netscape.security.x509.Extension;
+import netscape.security.x509.Extensions;
+import netscape.security.x509.KeyUsageExtension;
+import netscape.security.x509.X500Name;
+import netscape.security.x509.X509CertImpl;
+import netscape.security.x509.X509Key;
+
 /**
  * Utility class for functions to be used by the RESTful installer.
  *
@@ -196,6 +197,8 @@ public class ConfigurationUtils {
     public static final Long MINUS_ONE = Long.valueOf(-1);
     public static final String DBUSER = "pkidbuser";
 
+    public static ConfigCertApprovalCallback certApprovalCallback = new ConfigCertApprovalCallback();
+
     public static boolean loginToken(CryptoToken token, String tokPwd) throws TokenException,
             IncorrectPasswordException {
         boolean rv = true;
@@ -229,6 +232,7 @@ public class ConfigurationUtils {
 
         CMS.debug("ConfigurationUtils: GET " + config.getServerURI() + path);
         PKIConnection connection = new PKIConnection(config);
+        if (certApprovalCallback == null) certApprovalCallback = ConfigurationUtils.certApprovalCallback;
         connection.setCallback(certApprovalCallback);
         return connection.get(path);
     }
@@ -245,6 +249,7 @@ public class ConfigurationUtils {
 
         CMS.debug("ConfigurationUtils: POST " + config.getServerURI() + path);
         PKIConnection connection = new PKIConnection(config);
+        if (certApprovalCallback == null) certApprovalCallback = ConfigurationUtils.certApprovalCallback;
         connection.setCallback(certApprovalCallback);
         return connection.post(path, content);
     }
@@ -256,6 +261,8 @@ public class ConfigurationUtils {
 
         IConfigStore cs = CMS.getConfigStore();
         ConfigCertApprovalCallback certApprovalCallback = new ConfigCertApprovalCallback();
+        // Ignore untrusted issuer to get cert chain.
+        certApprovalCallback.ignoreError(ValidityStatus.UNTRUSTED_ISSUER);
         String c = get(host, port, true, serverPath, null, certApprovalCallback);
 
         if (c != null) {
-- 
2.5.5

