2

I am working hard on an open project to implement Libimobiledevice library in Java.

I already had implement Usbmuxd / PlistService / DeviceConnexion etc..

All working good, except when I am trying to wrap the SSL Socket.

According to the different implementation made in C (Libimobiledevice) or in Python (pymobiledevice), I generate the X509Certificat using the PEM provided during the Host & Device pairing.

I use this following PEM to generate my X509Certificat (first generated using libimobiledevice) :

-----BEGIN CERTIFICATE-----
MIICujCCAaKgAwIBAgIBADANBgkqhkiG9w0BAQUFADAAMB4XDTIxMDExMjE0MDcy
OVoXDTMxMDExMDE0MDcyOVowADCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAMtALTNIPEv1KjnzSarFl5ahC6UB9SMCRZbaPP3270Fxl8BW8BcbhqEn5j5K
pB+f+f4QXSh8ITx2/LPPuwd2YNlpR+pYmvKCLZRTxyrNLDY5srj3bIxAcJKIcuiQ
zISbGxNd/1jK52Y6ZmB9ntFpK094ZCL40TRvlghlzdYhS9Fr82OvIetyC+WXn64D
+gyrrtASvydOSzyiVJELDWe7ULHsVSafBBOL76BOmA6g4iruFujuMfrxFydg5RGp
TwTe9VnwJJO1xuKTlgMP9zQKxTP0EoEOGJ+rcqfmwExYRELQe4YwAkEKiq48BIxp
WHMo88Kj6MFmCnaDY9is18g+2yUCAwEAAaM/MD0wDAYDVR0TAQH/BAIwADAdBgNV
HQ4EFgQUHx2bzAmGPtEdlX34YL6pu9cfqMkwDgYDVR0PAQH/BAQDAgWgMA0GCSqG
SIb3DQEBBQUAA4IBAQDQeLnRXk3LWVBdZ7OzgtmHM236bDms2dgBPZv3WfTSHriT
l3PTssO08elH6/WAT2ljRluu3jtkwaqwKsEsG+8XAoMyHbW8VmzqC+PNou0PZPpY
cLMqTVdDq+9Do1AyQ8i3V16GGCxBb8NCHyfUcRnnq04KiuwaKBwWtttpTwMoAkYB
I+aH1drtRDiBcxuALZqEcAg5jfatgaRfgWsWNE0NJiXdk1PHUcF9dBOUhNttp1AS
THwqJXdBEiPc00zRlUQEx5Wu5pO4SVvhwbEM1F00srcDK6yYz0s+23eU7XLH6bGd
ik7hOSZjkEP/mmkrYHZUYYY9obpFbtLLsTWp0b0S
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDLQC0zSDxL9So5
80mqxZeWoQulAfUjAkWW2jz99u9BcZfAVvAXG4ahJ+Y+SqQfn/n+EF0ofCE8dvyz
z7sHdmDZaUfqWJrygi2UU8cqzSw2ObK492yMQHCSiHLokMyEmxsTXf9YyudmOmZg
fZ7RaStPeGQi+NE0b5YIZc3WIUvRa/NjryHrcgvll5+uA/oMq67QEr8nTks8olSR
Cw1nu1Cx7FUmnwQTi++gTpgOoOIq7hbo7jH68RcnYOURqU8E3vVZ8CSTtcbik5YD
D/c0CsUz9BKBDhifq3Kn5sBMWERC0HuGMAJBCoquPASMaVhzKPPCo+jBZgp2g2PY
rNfIPtslAgMBAAECggEBAJblvqkkKB/8lK0Rgs/WgwTB6/NF0Ml9Fk05Ga8zdc4Q
l6mk4ftF5F4hUT9OCyuvidqmK4OzJLnPXS3iO+j+akj/cPT7c444N763tFaCnSBl
FdtdVqmJ7gncY/NmDXEl9qQaVUmG2uV61ictHIw8mHsX1sBgGnHjpm/1pSwk7DU9
rC8ZsaNlDhEWGETohqXxUvK0e1MXNWWjg+XNSYrkj8b0f6SLKOFQcUQqreGDyg5I
uz/5pS6IGpetqWt43WbcgeRAELhtWBZsJgWv07Esf52RIqY1tW12QCguJUTP+Hqv
qfO7B+RJcv+m1Y4KEfMbShcl+SbMNagtjOQzGNmhlAECgYEA+J8ryB1cUdIuxtgG
EPBy+2JCb1Hjr8mIvdzuBj9Mbtlp9/n1tGCsex2T+Ct8IkohS/lOMgGXy+aw+Ats
pW9Z0XfEucyg8WgZ7zRPl83YIMDAXkOEQhNxZ+mgBHKPFCKLGzLOL392Le7niUxw
CX6mNVkKesP1Tn2gm+g+I3lMzNUCgYEA0UhP/tGV2G76hK3qp/X15ao3yG2FgEZv
qFU7rIi/jrJaFwCpPZ4y828iv3nScSgBBSUOKwhY/k+LTPHaSkpgeX5Rhpj1mW+t
cVeEjbHLAlhX/FivfaJOLJfQTU2YChqA9Ax5VVPMTjhVS77BU68omUZpG2xzBp6K
clDn8XE8vRECgYEA4kEwPcACeO+W5BxJgPbhHMZyAQ5770ivqWE6N/M44pP27NXL
9agYrz3en/Uq1aWyoYoy0C1E8ClzmXgEGpW4HnkpTZDcUnTTTS3E1Thd3IitR9uX
q+43wUIJ/qImdUNuZoUYwH71lJ2algc62lkodtoeQFS+k/ydweRbUDseWjUCgYEA
yscSG4jfc9I0EhKhZxS+qUUAv8a+r8ePsL7FDyuAz7an69nMIdQC8jQgqv5SlSl5
s45v5+oysFZKVseQBqOCTrXCMHRMo9q9ZzCxUsmONjt7JRqZD1YQAM0oG36vbjq3
77+WYMLNFo0muDmgAIGbCMhcVyIBYcyDwLf7xMk/XMECgYBim0gMEYAE+2U2b1wm
5CnTDcObOTf2cUh56YWwPOlmQIbXKQxlEajCBYCfX51HHi0TyozutJ9oFuGQJzzH
h4UHmSykionM7KTgQOtnEbYVzTSyx4wlQWciHSHUZ3RhOGTM1jbeTXTUXwcXVfLA
z0UpDK0tm1S3o/aQFS1RkX+chg==
-----END PRIVATE KEY-----

When I decode this PEM File , I can see there is no DN provided in this key.

And during the SSLHandshake I receive this Exception :

Exception in thread "main" java.io.IOException: java.io.IOException: javax.net.ssl.SSLProtocolException: Empty issuer DN not allowed in X509Certificates

And this is the part of my code causing this Exception :

SSLSocket sslSocket = (SSLSocket) SSLContext.getDefault().getSocketFactory().createSocket(socket, "127.0.0.1", 62078, true);
                System.out.println("Socket open");
                
                sslSocket.setEnabledCipherSuites(new String[] { "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384" });
                sslSocket.setEnabledProtocols(new String[] { "TLSv1.2" });
                try{
                    sslSocket.startHandshake();
                    System.out.println("================================Socket open success");
                }catch(Exception e){
                    throw new IOException(e);
                }

There is a way to bypass the "Empty issuer Exception" in Java ? or Someone do have an other idea ? I really need your help on this.

Thank you.

De Filippi JM
  • 21
  • 1
  • 2
  • 1
    It seems an empty subject DN is valid per [RFC 5280](https://tools.ietf.org/rfc/rfc5280.txt), but an empty subject DN (or issuer DN) may mean the certificate is not valid for use in an SSL connection. – Andrew Henle Jan 12 '21 at 21:29
  • You may be able to disable hostname validation. https://www.google.com/search?q=java+disable+ssl+hostname+verification There's no name on the cert to verify anyway. The certificate itself should still be validated against your truststore, though, so it should still be secure. – Andrew Henle Jan 12 '21 at 22:20
  • Trying to add this java option -Dtrust_all_cert=true but nothing change. – De Filippi JM Jan 12 '21 at 22:36
  • According to this line on pymobile project `ssl.wrap_socket(self.s, keyfile, certfile, ssl_version=ssl.PROTOCOL_TLSv1)` the keyfile and certfile seem to use the PEM file provided in my code – De Filippi JM Jan 12 '21 at 22:37
  • @AndrewHenle in complement during the SSL handshake the `Socket Write` seem working good. Only when the `Socket Read` the answer I got this Exception. – De Filippi JM Jan 12 '21 at 22:44
  • *Trying to add this java option -Dtrust_all_cert=true but nothing change.* I'm pretty sure all that does is assume the certificate is trusted - it doesn't have to check if that cert is either in your trust store or signed by a cert in your trust store. It's still going to do host name verification to make sure the SSL connect is to the server it's supposed to go to - there might be a Java property to skip that, but I don't think so. You're probably going to have to code up a null host name verifier and use it in a custom SSLContext. – Andrew Henle Jan 13 '21 at 10:07

1 Answers1

0

I'm create a tool with compose-jb, same problem. Finally I modify OpenJDK18 solved this problem.

Patch:

Index: src/java.base/share/classes/sun/security/ssl/CertificateMessage.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java b/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java
--- a/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java  (revision 70d808deca55534a5a1376cccd0a35202d4fc091)
+++ b/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java  (revision 74ae6f2acacb6ea332e9413d2d3da75af3c7fac9)
@@ -635,10 +635,14 @@
                             engine);
                     } else {
                         SSLSocket socket = (SSLSocket)chc.conContext.transport;
-                        ((X509ExtendedTrustManager)tm).checkServerTrusted(
-                            certs.clone(),
-                            keyExchangeString,
-                            socket);
+                        // Unix Socket skip check
+                        // Windows usbmuxd on port 27015 skip check
+                        if(!(socket.getPort() == 0 || socket.getPort() == 27015)){
+                            ((X509ExtendedTrustManager)tm).checkServerTrusted(
+                                    certs.clone(),
+                                    keyExchangeString,
+                                    socket);
+                        }
                     }
                 } else {
                     // Unlikely to happen, because we have wrapped the old
Index: src/java.base/share/classes/sun/security/x509/X509CertInfo.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/java.base/share/classes/sun/security/x509/X509CertInfo.java b/src/java.base/share/classes/sun/security/x509/X509CertInfo.java
--- a/src/java.base/share/classes/sun/security/x509/X509CertInfo.java   (revision 70d808deca55534a5a1376cccd0a35202d4fc091)
+++ b/src/java.base/share/classes/sun/security/x509/X509CertInfo.java   (revision 74ae6f2acacb6ea332e9413d2d3da75af3c7fac9)
@@ -655,8 +655,9 @@
         // Issuer name
         issuer = new X500Name(in);
         if (issuer.isEmpty()) {
-            throw new CertificateParsingException(
-                "Empty issuer DN not allowed in X509Certificates");
+            issuer = new X500Name("");
+//            throw new CertificateParsingException(
+//                "Empty issuer DN not allowed in X509Certificates");
         }
 
         // validity:  SEQUENCE { start date, end date }
@@ -710,7 +711,9 @@
         }
 
         // verify X.509 V3 Certificate
-        verifyCert(subject, extensions);
+        if(!issuer.isEmpty()){
+            verifyCert(subject, extensions);
+        }
 
     }
 

Or $openJDK18Dir/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java
near line 638

                        // Unix Socket skip check
                        // Windows usbmuxd on port 27015 skip check
                        if(!(socket.getPort() == 0 || socket.getPort() == 27015)){
                            ((X509ExtendedTrustManager)tm).checkServerTrusted(
                                    certs.clone(),
                                    keyExchangeString,
                                    socket);
                        }

$openJDK18Dir/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java private void parse(DerValue val)

    issuer = new X500Name("");

    if(!issuer.isEmpty()){
        verifyCert(subject, extensions);
    }

Attect
  • 1
  • 2