[Pki-devel] [PATCH] 0051 Lightweight CAs: lookup correct issuer for OCSP responses

Fraser Tweedale ftweedal at redhat.com
Wed Mar 2 05:13:58 UTC 2016


On Mon, Feb 22, 2016 at 12:02:49PM -0500, Ade Lee wrote:
> Couple of comments ..
> 
> 1. First off, there is a typo in the comments on the method.  I think
> you mean ..  
> 
>     3. Either we WERE the issuing CA, or we .. rather than "were not"
> 
> 2. We can go with the heuristic of taking the first CA, but I do not
> think we should leak information about other certs if the CA is
> incorrect.  The way the code is now, we will still return data on
> whether a particular cert serial number is valid -- even if that cert
> was not issued on that CA.
> 
> A simple solution is to simply pass code to processRequest() to ignore
> the request if the issuer is not correct and not return a response for
> that request.
> 
RFC 6960 says:

    The response MUST include a SingleResponse for each certificate
    in the request.

So the best we can do is return 'unknown' status in this case.

I've attached updated patch 0051-2 - the only change is the comment
fixup - and two new patches: 0074 refactors digest lookup and adds
support for SHA-2 algos, and 0075 changes the OCSP behaviour to
return 'unknown' cert status for certs that from a different issuer.

Cheers,
Fraser
-------------- next part --------------
From f24c753bde6f744d64a06fbe6c07a55575085691 Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftweedal at redhat.com>
Date: Thu, 1 Oct 2015 08:26:01 -0400
Subject: [PATCH] Lightweight CAs: lookup correct issuer for OCSP responses

---
 .../src/com/netscape/ca/CertificateAuthority.java  | 39 +++++++++++++++++++++-
 1 file changed, 38 insertions(+), 1 deletion(-)

diff --git a/base/ca/src/com/netscape/ca/CertificateAuthority.java b/base/ca/src/com/netscape/ca/CertificateAuthority.java
index 889e7e3f7595a0f831c61cecec6ee2c8fa462d44..cbb155a3bedd1517256b89ab8d2803d6ccbbb8c5 100644
--- a/base/ca/src/com/netscape/ca/CertificateAuthority.java
+++ b/base/ca/src/com/netscape/ca/CertificateAuthority.java
@@ -2121,12 +2121,49 @@ public class CertificateAuthority implements ICertificateAuthority, ICertAuthori
             return null;
         }
 
+        TBSRequest tbsReq = request.getTBSRequest();
+
+        /* An OCSP request can contain CertIDs for certificates
+         * issued by different CAs, but each SingleResponse is valid
+         * only if the combined response was signed by its issuer or
+         * an authorised OCSP signing delegate.
+         *
+         * Even though it is silly to send an OCSP request
+         * asking about certs issued by different CAs, we must
+         * employ some heuristic to deal with this case. Our
+         * heuristic is:
+         *
+         * 1. Find the issuer of the cert identified by the first
+         *    CertID in the request.
+         *
+         * 2. If this CA is *not* the issuer, look up the issuer
+         *    by its DN in the caMap.  If not found, fail.  If
+         *    found, dispatch to its 'validate' method.  Otherwise
+         *    continue.
+         *
+         * 3. If this CA is NOT the issuing CA, we locate the
+         *    issuing CA and dispatch to its 'validate' method.
+         *    Otherwise, we move forward to generate and sign the
+         *    aggregate OCSP response.
+         */
+        ICertificateAuthority ocspCA = this;
+        if (tbsReq.getRequestCount() > 0) {
+            com.netscape.cmsutil.ocsp.Request req = tbsReq.getRequestAt(0);
+            BigInteger serialNo = req.getCertID().getSerialNumber();
+            X509CertImpl cert = mCertRepot.getX509Certificate(serialNo);
+            X500Name certIssuerDN = (X500Name) cert.getIssuerDN();
+            ocspCA = getCA(certIssuerDN);
+        }
+        if (ocspCA == null)
+            throw new CANotFoundException("Could not locate issuing CA");
+        if (ocspCA != this)
+            return ((IOCSPService) ocspCA).validate(request);
+
         mNumOCSPRequest++;
         IStatsSubsystem statsSub = (IStatsSubsystem) CMS.getSubsystem("stats");
         long startTime = CMS.getCurrentDate().getTime();
         try {
             //log(ILogger.LL_INFO, "start OCSP request");
-            TBSRequest tbsReq = request.getTBSRequest();
 
             // (3) look into database to check the
             //     certificate's status
-- 
2.5.0

-------------- next part --------------
From bc2461f2051247f59b68ba39d0eba9796b3ddfe0 Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftweedal at redhat.com>
Date: Tue, 1 Mar 2016 20:46:49 -0500
Subject: [PATCH 74/75] Move OCSP digest name lookup to CertID class

The OCSP digest name lookup is currently defined in IOCSPAuthority
and implemented by OCSPAuthority, but /any/ code that deals with
CertID might need to know the digest, so move the lookup there.

Also refactor the lookup to use a HashMap, and add mappings for SHA2
algorithms.
---
 .../com/netscape/certsrv/ocsp/IOCSPAuthority.java   |  9 ---------
 base/ocsp/src/com/netscape/ocsp/OCSPAuthority.java  | 21 ---------------------
 .../cms/src/com/netscape/cms/ocsp/DefStore.java     |  3 +--
 .../cms/src/com/netscape/cms/ocsp/LDAPStore.java    |  3 +--
 base/util/src/com/netscape/cmsutil/ocsp/CertID.java | 19 +++++++++++++++++++
 5 files changed, 21 insertions(+), 34 deletions(-)

diff --git a/base/common/src/com/netscape/certsrv/ocsp/IOCSPAuthority.java b/base/common/src/com/netscape/certsrv/ocsp/IOCSPAuthority.java
index 6164b4917181d0181c73eabd0a7a9c3fe265e2de..3264d2ce5f1dbb88172e9ac124168af5acf7930b 100644
--- a/base/common/src/com/netscape/certsrv/ocsp/IOCSPAuthority.java
+++ b/base/common/src/com/netscape/certsrv/ocsp/IOCSPAuthority.java
@@ -144,15 +144,6 @@ public interface IOCSPAuthority extends ISubsystem {
     public X500Name getName();
 
     /**
-     * This method retrieves an OCSP server instance digest name as a string.
-     * <P>
-     *
-     * @param alg the signing algorithm
-     * @return String the digest name of the related OCSP server
-     */
-    public String getDigestName(AlgorithmIdentifier alg);
-
-    /**
      * This method signs the basic OCSP response data provided as a parameter.
      * <P>
      *
diff --git a/base/ocsp/src/com/netscape/ocsp/OCSPAuthority.java b/base/ocsp/src/com/netscape/ocsp/OCSPAuthority.java
index eb9060663c0ff5336cf7d4d0736b6d6284d2ae49..e6fd87da0770a2e85958112765464fccbd26cb05 100644
--- a/base/ocsp/src/com/netscape/ocsp/OCSPAuthority.java
+++ b/base/ocsp/src/com/netscape/ocsp/OCSPAuthority.java
@@ -257,27 +257,6 @@ public class OCSPAuthority implements IOCSPAuthority, IOCSPService, ISubsystem,
         return mOCSPSigningAlgorithms;
     }
 
-    public static final OBJECT_IDENTIFIER MD2 =
-            new OBJECT_IDENTIFIER("1.2.840.113549.2.2");
-    public static final OBJECT_IDENTIFIER MD5 =
-            new OBJECT_IDENTIFIER("1.2.840.113549.2.5");
-    public static final OBJECT_IDENTIFIER SHA1 =
-            new OBJECT_IDENTIFIER("1.3.14.3.2.26");
-
-    public String getDigestName(AlgorithmIdentifier alg) {
-        if (alg == null) {
-            return null;
-        } else if (alg.getOID().equals(MD2)) {
-            return "MD2";
-        } else if (alg.getOID().equals(MD5)) {
-            return "MD5";
-        } else if (alg.getOID().equals(SHA1)) {
-            return "SHA1"; // 1.3.14.3.2.26
-        } else {
-            return null;
-        }
-    }
-
     /**
      * Retrieves the name of this OCSP server.
      */
diff --git a/base/server/cms/src/com/netscape/cms/ocsp/DefStore.java b/base/server/cms/src/com/netscape/cms/ocsp/DefStore.java
index 86e0c68b1b40a90c1647abaeccbec983b2d7ee49..217c56833ca660176702c9badf5e14d286482908 100644
--- a/base/server/cms/src/com/netscape/cms/ocsp/DefStore.java
+++ b/base/server/cms/src/com/netscape/cms/ocsp/DefStore.java
@@ -449,8 +449,7 @@ public class DefStore implements IDefStore, IExtendedPluginInfo {
                         log(ILogger.LL_FAILURE, CMS.getLogMessage("OCSP_DECODE_CERT", e.toString()));
                         return null;
                     }
-                    MessageDigest md = MessageDigest.getInstance(
-                            mOCSPAuthority.getDigestName(cid.getHashAlgorithm()));
+                    MessageDigest md = MessageDigest.getInstance(cid.getDigestName());
                     X509Key key = (X509Key) cert.getPublicKey();
                     byte digest[] = md.digest(key.getKey());
 
diff --git a/base/server/cms/src/com/netscape/cms/ocsp/LDAPStore.java b/base/server/cms/src/com/netscape/cms/ocsp/LDAPStore.java
index e2e5fc4937d626d70a15946bb6a839c43440ce29..0d2d608bf057ac281e3a8c1ae1da597579a25c5e 100644
--- a/base/server/cms/src/com/netscape/cms/ocsp/LDAPStore.java
+++ b/base/server/cms/src/com/netscape/cms/ocsp/LDAPStore.java
@@ -466,8 +466,7 @@ public class LDAPStore implements IDefStore, IExtendedPluginInfo {
             MessageDigest md = null;
 
             try {
-                md = MessageDigest.getInstance(
-                            mOCSPAuthority.getDigestName(cid.getHashAlgorithm()));
+                md = MessageDigest.getInstance(cid.getDigestName());
             } catch (Exception e) {
             }
             X509Key key = (X509Key) caCert.getPublicKey();
diff --git a/base/util/src/com/netscape/cmsutil/ocsp/CertID.java b/base/util/src/com/netscape/cmsutil/ocsp/CertID.java
index 23668f194da1b383b6023984fd5a6f27b1718bd7..2a1f398ff47d911e38da0366dc79c8d1f7443f73 100644
--- a/base/util/src/com/netscape/cmsutil/ocsp/CertID.java
+++ b/base/util/src/com/netscape/cmsutil/ocsp/CertID.java
@@ -20,11 +20,13 @@ package com.netscape.cmsutil.ocsp;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.util.HashMap;
 
 import org.mozilla.jss.asn1.ASN1Template;
 import org.mozilla.jss.asn1.ASN1Value;
 import org.mozilla.jss.asn1.INTEGER;
 import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.asn1.OBJECT_IDENTIFIER;
 import org.mozilla.jss.asn1.OCTET_STRING;
 import org.mozilla.jss.asn1.SEQUENCE;
 import org.mozilla.jss.asn1.Tag;
@@ -152,4 +154,21 @@ public class CertID implements ASN1Value {
                     (INTEGER) seq.elementAt(3));
         }
     }
+
+
+    private static HashMap<OBJECT_IDENTIFIER, String> digestNames = new HashMap<>();
+
+    static {
+        digestNames.put(new OBJECT_IDENTIFIER("1.2.840.113549.2.2"), "MD2");
+        digestNames.put(new OBJECT_IDENTIFIER("1.2.840.113549.2.5"), "MD5");
+        digestNames.put(new OBJECT_IDENTIFIER("1.3.14.3.2.26"), "SHA-1");
+        digestNames.put(new OBJECT_IDENTIFIER("2.16.840.1.101.3.4.2.4"), "SHA-224");
+        digestNames.put(new OBJECT_IDENTIFIER("2.16.840.1.101.3.4.2.1"), "SHA-256");
+        digestNames.put(new OBJECT_IDENTIFIER("2.16.840.1.101.3.4.2.2"), "SHA-384");
+        digestNames.put(new OBJECT_IDENTIFIER("2.16.840.1.101.3.4.2.3"), "SHA-512");
+    }
+
+    public String getDigestName() {
+        return digestNames.get(hashAlgorithm.getOID());
+    }
 }
-- 
2.5.0

-------------- next part --------------
From c8edfcfb27a457a675d8e194acb59891a6e839ed Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftweedal at redhat.com>
Date: Tue, 1 Mar 2016 22:38:40 -0500
Subject: [PATCH 75/75] Do not leak status of certs issued by other CAs

If an OCSP request includes CertIDs for certificates issued by
multiple CAs, return 'unknown' CertStatus for all certificates not
issued by the "signing" CA.
---
 base/ca/src/com/netscape/ca/CertificateAuthority.java | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/base/ca/src/com/netscape/ca/CertificateAuthority.java b/base/ca/src/com/netscape/ca/CertificateAuthority.java
index cbb155a3bedd1517256b89ab8d2803d6ccbbb8c5..63c7ca4e4a8083dc58b54196af89cc7629e9fd97 100644
--- a/base/ca/src/com/netscape/ca/CertificateAuthority.java
+++ b/base/ca/src/com/netscape/ca/CertificateAuthority.java
@@ -33,6 +33,7 @@ import java.security.Signature;
 import java.security.cert.CRLException;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateParsingException;
+import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
@@ -2245,7 +2246,7 @@ public class CertificateAuthority implements ICertificateAuthority, ICertAuthori
             return response;
         } catch (Exception e) {
             log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CA_OCSP_REQUEST", e.toString()));
-            throw new EBaseException(e.toString());
+            throw new EBaseException(e.toString(), e);
         }
     }
 
@@ -2301,6 +2302,22 @@ public class CertificateAuthority implements ICertificateAuthority, ICertAuthori
         GeneralizedTime thisUpdate = new GeneralizedTime(CMS.getCurrentDate());
         GeneralizedTime nextUpdate = null;
 
+        byte[] nameHash = null;
+        String digestName = cid.getDigestName();
+        if (digestName != null) {
+            try {
+                MessageDigest md = MessageDigest.getInstance(digestName);
+                nameHash = md.digest(mName.getEncoded());
+            } catch (NoSuchAlgorithmException | IOException e) {
+            }
+        }
+        if (!Arrays.equals(cid.getIssuerNameHash().toByteArray(), nameHash)) {
+            // issuer of cert is not this CA (or we couldn't work
+            // out whether it is or not due to unknown hash alg);
+            // do not return status information for this cert
+            return new SingleResponse(cid, new UnknownInfo(), thisUpdate, null);
+        }
+
         boolean ocspUseCache = true;
 
         try {
-- 
2.5.0



More information about the Pki-devel mailing list