Home » Android » java – need help understanding certificate chains

java – need help understanding certificate chains

Posted by: admin May 14, 2020 Leave a comment

Questions:

At the moment I am writing a java library to access the REST API of pointhq.com.

While developing a Android client I realized that the SSL certificate is not accepted by default so I wrote a custom TrustManager and added the pointhq.com certificate like explained in this post: Trusting all certificates using HttpClient over HTTPS

Using this Trustmanager and my imported bks file I get the following error while trying to connect: IssuerName(CN=GeoTrust Global CA, O=GeoTrust Inc., C=US) does not match SubjectName(CN=RapidSSL CA, O="GeoTrust, Inc.", C=US) of signing certificate.

So what did I do wrong? I imported the pointhq.com, rapidssl.com, geotrust.com certificates. But nothing changed. Is there a kind of sorting of certificates I have to be aware of? Am I missing a root certificate?

EDIT: Here is the list of imported certificates:

Type: BKS
Provider: BC
Entries: 3

Entry Alias: geotrust global ca
Creation Date: 19.10.2011 15:44:35 MESZ
Type: Trusted Certificate
Certificates: 1

Certificate 1 of 1
Version: 3
Subject: CN=GeoTrust Global CA, O=GeoTrust Inc., C=US
Issuer: CN=GeoTrust Global CA, O=GeoTrust Inc., C=US
Serial Number: 0002 3456
Valid From: 21.05.2002 06:00:00
Valid Until: 21.05.2022 06:00:00
Public Key: RSA (2.048 bits)
Signature Algorithm: SHA1withRSA
SHA-1 Fingerprint: DE:28:F4:A4:FF:E5:B9:2F:A3:C5:03:D1:A3:49:A7:F9:96:2A:82:12
MD5 Fingerprint: F7:75:AB:29:FB:51:4E:B7:77:5E:FF:05:3C:99:8E:F5

Entry Alias: pointhq.com (rapidssl ca)
Creation Date: 29.09.2011 18:55:12 MESZ
Type: Trusted Certificate
Certificates: 1

Certificate 1 of 1
Version: 3
Subject: CN=pointhq.com, OU=Domain Control Validated - RapidSSL(R), OU=See www.rapidssl.com/resources/cps (c)11, OU=GT70151377, O=pointhq.com, C=GB, SERIALNUMBER=8Dvj7qRSYLjGZiX2tHocE2FDaqAp8RwO
Issuer: CN=RapidSSL CA, O="GeoTrust, Inc.", C=US
Serial Number: 8971
Valid From: 31.01.2011 13:20:09
Valid Until: 03.02.2013 09:15:38
Public Key: RSA (2.048 bits)
Signature Algorithm: SHA1withRSA
SHA-1 Fingerprint: BB:04:D0:3E:1A:36:02:F7:C3:8C:85:99:1D:67:2A:6B:CF:C1:BC:C5
MD5 Fingerprint: 21:9D:DF:72:E6:4A:33:47:E1:BA:D6:52:86:1E:59:B4

Entry Alias: rapidssl ca (geotrust global ca)
Creation Date: 29.09.2011 18:54:49 MESZ
Type: Trusted Certificate
Certificates: 1

Certificate 1 of 1
Version: 3
Subject: CN=RapidSSL CA, O="GeoTrust, Inc.", C=US
Issuer: CN=GeoTrust Global CA, O=GeoTrust Inc., C=US
Serial Number: 0002 36D1
Valid From: 19.02.2010 23:45:05
Valid Until: 18.02.2020 23:45:05
Public Key: RSA (2.048 bits)
Signature Algorithm: SHA1withRSA
SHA-1 Fingerprint: C0:39:A3:26:9E:E4:B8:E8:2D:00:C5:3F:A7:97:B5:A1:9E:83:6F:47
MD5 Fingerprint: 1B:EE:28:5E:8F:F8:08:5F:79:CC:60:8B:92:99:A4:53

I now wrote an SSL Test app. The results are confusing.
As you can see on the attached screenshots, sometimes the ssl connection is accepted and some times its not! Even if it is the same site that I’m connecting to.

https://ssltest12.bbtest.net/ is the demo site for the RapidSSL certificate I what to use. As you can see on the Android 2.1 Screenshot the first connection get’s not accepted the but the second try works perfectly fine, while the last doesn’t work again. How can that happen?

BTW: Since Android 2.3.3 the RapidSSL certificate is accepted without any custom code!

Scrennshots:

How to&Answers:

Yes, the order of certificates in chain matter. Basically you want certificates to be odered from yours to CA. Browsers do it for you, but Java does not. I had the issue with unordered certificates in chain and I ended up writing a simple implementation of X509TrustManager with:

    public void checkServerTrusted(X509Certificate[] certificates,String authType) throws CertificateException {
    if ((certificates != null) && LOG.isDebugEnabled()) {
        LOG.debug("Server certificate chain:");
        for (int i = 0; i < certificates.length; i++) {
            LOG.debug("X509Certificate[" + i + "]=" + certificates[i]);
        }
    }
    if ((certificates != null) && (certificates.length == 1)) {
        certificates[0].checkValidity();
    } else {
        List<X509Certificate> certs = new ArrayList<X509Certificate>();
        certs.addAll(Arrays.asList(certificates));
        X509Certificate certChain = certs.get(0);
        certs.remove(certChain);
        LinkedList<X509Certificate> chainList= new LinkedList<X509Certificate>();
        chainList.add(certChain);
        Principal certIssuer = certChain.getIssuerDN();
        Principal certSubject = certChain.getSubjectDN();
        while(!certs.isEmpty()){
            List<X509Certificate> tempcerts = new ArrayList<X509Certificate>();
            tempcerts.addAll(certs);
            for (X509Certificate cert : tempcerts){
                if(cert.getIssuerDN().equals(certSubject)){
                    chainList.addFirst(cert);
                    certSubject = cert.getSubjectDN();
                    certs.remove(cert);
                    continue;
                }

                if(cert.getSubjectDN().equals(certIssuer)){
                    chainList.addLast(cert);
                    certIssuer = cert.getIssuerDN();
                    certs.remove(cert);
                    continue;
                }
            }
        }
    standardTrustManager.checkServerTrusted(chainList.toArray(new X509Certificate[]{}),authType);

    }
}

Notice the ordering “while” cycle.