JDK-7142172 : Custom X509TrustManagers that return null for getAcceptedIssuers will NPE.
  • Type: Bug
  • Component: security-libs
  • Sub-Component: javax.net.ssl
  • Affected Version: 7,7u4
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: generic,os_x,windows_7
  • CPU: generic,x86
  • Submitted: 2012-02-02
  • Updated: 2016-04-29
  • Resolved: 2012-04-13
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 6 JDK 7 JDK 8
6u115Fixed 7u4 b20Fixed 8Fixed
Related Reports
Duplicate :  
Duplicate :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.7.0_04-ea"
Java(TM) SE Runtime Environment (build 1.7.0_04-ea-b227)
Java HotSpot(TM) 64-Bit Server VM (build 23.0-b12, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Mac OS X 10.7.3

A DESCRIPTION OF THE PROBLEM :
I receive the following exception when running on JDK 7 on OS X.  JDK 7 on Windows or Linux works, as does JDK 6 on OS X.

java.lang.NullPointerException
	at java.util.Collections.addAll(Collections.java:3836)
	at sun.security.ssl.AbstractTrustManagerWrapper.<init>(SSLContextImpl.java:778)
	at sun.security.ssl.SSLContextImpl.chooseTrustManager(SSLContextImpl.java:133)
	at sun.security.ssl.SSLContextImpl.engineInit(SSLContextImpl.java:89)
	at javax.net.ssl.SSLContext.init(SSLContext.java:283)

REGRESSION.  Last worked in version 6u29

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
We encounter the issue while running the example code attached
 


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Should not throw an exception
ACTUAL -
throws NPE

ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.lang.NullPointerException
	at java.util.Collections.addAll(Collections.java:3836)
	at sun.security.ssl.AbstractTrustManagerWrapper.<init>(SSLContextImpl.java:778)
	at sun.security.ssl.SSLContextImpl.chooseTrustManager(SSLContextImpl.java:133)
	at sun.security.ssl.SSLContextImpl.engineInit(SSLContextImpl.java:89)
	at javax.net.ssl.SSLContext.init(SSLContext.java:283)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
package testssl;

import java.security.PublicKey;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import sun.misc.BASE64Encoder;

public class TestSSL {

    public static void main(String[] args) throws Exception {
        final String CERT_PBK = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCd8j2M0Ok94KVfY1wxcb6RGfHbBK2NggrDmgF60/nzQmU3Z92AYxDUqXXl9j3SsvTLwgh0HpQgTgkOeJ/1csYMy+Ij1ZtRQ2IReBd9KvCbgpmZA5o0Hgf5bT0Jh6XyJI0cGIZ5PS9lhkJcfBVcEiPMlfvo6ZxaU/Kes6BHG7yWFQIDAQAB";
        SSLContext sslContext;


        // Create a trust manager that does not validate certificate chains
        TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {

        public void checkClientTrusted(
                java.security.cert.X509Certificate[] certs, String authType) {
        }

        public void checkServerTrusted(
                java.security.cert.X509Certificate[] certs, String authType) {
            if (certs.length == 1) {
                PublicKey publicKey = certs[0].getPublicKey();
                byte[] encodePublickey = publicKey.getEncoded();
                String s = new BASE64Encoder().encode(encodePublickey);
                if (s.compareTo(CERT_PBK) != 0) {
                    throw new Error("invalid key");
                }
            } else {
                throw new Error("Unexpected number of certs");
            }

        }

        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    }};

        sslContext = javax.net.ssl.SSLContext.getInstance("SSL");
        sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
    }
}

---------- END SOURCE ----------

Comments
EVALUATION I prefer to checking the null value before adding it to the collection. Please note that if X509TrustManager.getAcceptedIssuers() does not return the expected trusted issuers as the specification required, it does not grant the application will work as expected during algorithm constraints checking. The algorithm constraints is expected to ignoring the trusted certificates checking (I think TM.getAcceptedIssuers() return null does not means that there is no trusted certificate), but if the accepted issuers is null or empty, the checking will be done on every cert in the chain.
30-03-2012

EVALUATION This is due to the change we put in for: 7113275: compatibility issue with MD2 trust anchor and old X509TrustManager In AbstractTrustManagerWrapper, which is used as a wrapper when the passed-in custom TM isn't a X509ExtendedTrustManager, we are now caching the accepted certificate issuers from the constructor to speed up future AlgorithmConstraints checks. The addAll(..., null) is throwing the NPE when getAcceptedIssuers is returning null. There is one other place that calls getAcceptedIssuers, and that's in the ServerHandshaker when we do client authentication. We'll also throw a NPE there if someone passes in a custom TM that has this behavior. However, I think this is not normally seen because most applications don't do client auth by default, and don't provide custom trustmanagers with this broken behavior. This behavior has been there since at least 1.4.2 FCS, so don't feel it's necessary to fix here. To fix it, we can either remove the caching, or we can check for null during the initialization. I'm leaning toward the latter, but the former is the safest.
30-03-2012

PUBLIC COMMENTS Please note that getAcceptedIssuers() API does not allow a null entry to be returned. It must be non-null, possibly empty. Close as "not a defect".
03-02-2012