2015-11-04 2 views
3

Для поддержки HTTPS соединений через Java 1.6 API для удаленных хостов с помощью TLS 1.2, мы разработали настраиваемую завод TLS SocketConnection основанный на Надувной замок библиотек (ст. 1.53)TLS 1.2 + Java 1.6 + BouncyCastle

Это очень простой в использовании, просто:

 String httpsURL = xxxxxxxxxx 
     URL myurl = new URL(httpsURL);  
     HttpsURLConnection con = (HttpsURLConnection)myurl.openConnection(); 
     con.setSSLSocketFactory(new TSLSocketConnectionFactory()); 
     InputStream ins = con.getInputStream(); 

во время тестирования я подключить различные веб и удаленные хосты подвергаются в SSLabs Tests

90% времени, это работает отлично! Но есть случаи, когда мы получаем раздражающую ошибку: «Внутренняя ошибка TLS, это может быть атака». Было проверено, что атаки нет. Это обычная ошибка, основанная на обработке внутренних исключений BouncyCastle. Я пытаюсь найти общий шаблон для тех удаленных хостов, которые не удались.

Обновлено:

Обновление код для дополнительной информации, мы получаем следующее:

org.bouncycastle.crypto.tls.TlsFatalAlert: illegal_parameter(47) 
    at org.bouncycastle.crypto.tls.AbstractTlsClient.checkForUnexpectedServerExtension(AbstractTlsClient.java:56) 
    at org.bouncycastle.crypto.tls.AbstractTlsClient.processServerExtensions(AbstractTlsClient.java:207) 
    at org.bouncycastle.crypto.tls.TlsClientProtocol.receiveServerHelloMessage(TlsClientProtocol.java:773) 

тип расширения я получаю это:

ExtensionType: 11 ExtensionData:

В соответствии с классом ExtensionType, "ec_point_fo rmats». Это вызывает «UnexpectedServerExtension» -> «UnexpectedServerExtension» вызывает a -> TlsFatalAlert: незаконный_параметр, и, наконец, это «Внутренняя ошибка TLS, это может быть атака»

Любые советы для регистрации или отслеживания этого странного TLS Ошибки .... ???? Как я говорю, этот код работает на 90% ... но с некоторым удаленным хостом я получаю эту errof

Хитрость заключается в переопределении startHandShake использовать Надувной в TLSClientProtocol:

  1. Переопределить ClientExtensions включить «хозяина» ExtensionType , Просто ExtensionType.server_name (может быть больше Удлинителя включить?)
  2. Создать TlsAuthentication включить remoteCerts на сокет peerCertificate .Такжа при необходимости проверить, если удаленные сертификаты в по умолчанию (хранилище cacerts, и т.д ..)

делюсь код TLSSocketConnectionFactory:

public class TLSSocketConnectionFactory extends SSLSocketFactory { 

////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
//Adding Custom BouncyCastleProvider 
/////////////////////////////////////////////////////////////////////////////////////////////////////////////// 

    static { 
     if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) { 
      Security.addProvider(new BouncyCastleProvider()); 
     } 
    } 

////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
//SECURE RANDOM 
////////////////////////////////////////////////////////////////////////////////////////////////////////////// 

    private SecureRandom _secureRandom = new SecureRandom(); 

////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
//Adding Custom BouncyCastleProvider 
/////////////////////////////////////////////////////////////////////////////////////////////////////////////// 

    @Override 
    public Socket createSocket(Socket socket, final String host, int port, boolean arg3) 
      throws IOException { 
     if (socket == null) { 
      socket = new Socket(); 
     } 
     if (!socket.isConnected()) { 
      socket.connect(new InetSocketAddress(host, port)); 
     } 

     final TlsClientProtocol tlsClientProtocol = new TlsClientProtocol(socket.getInputStream(), socket.getOutputStream(), _secureRandom);  

     return _createSSLSocket(host, tlsClientProtocol); 

    } 

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
// SOCKET FACTORY METHODS 
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 

    @Override 
    public String[] getDefaultCipherSuites() { 
     return null; 
    } 

    @Override 
    public String[] getSupportedCipherSuites(){ 
     return null; 
    } 

    @Override 
    public Socket createSocket(String host, 
           int port) throws IOException,UnknownHostException{ 
     return null; 
    } 

    @Override 
    public Socket createSocket(InetAddress host, 
           int port) throws IOException { 
     return null; 
    } 

    @Override 
    public Socket createSocket(String host, 
           int port, 
           InetAddress localHost, 
           int localPort) throws IOException, UnknownHostException { 
     return null; 
    } 

    @Override 
    public Socket createSocket(InetAddress address, 
           int port, 
           InetAddress localAddress, 
           int localPort) throws IOException{ 
     return null; 
    } 

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
//SOCKET CREATION 
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 

    private SSLSocket _createSSLSocket(final String host , final TlsClientProtocol tlsClientProtocol) { 
     return new SSLSocket() { 
      private java.security.cert.Certificate[] peertCerts; 

      @Override 
      public InputStream getInputStream() throws IOException { 
       return tlsClientProtocol.getInputStream(); 
      } 

      @Override 
      public OutputStream getOutputStream() throws IOException { 
       return tlsClientProtocol.getOutputStream(); 
      } 

      @Override 
      public synchronized void close() throws IOException { 
       Log.to("util").info("\\\n::::::Close Socket"); 
       tlsClientProtocol.close(); 
      } 

      @Override 
      public void addHandshakeCompletedListener(HandshakeCompletedListener arg0) { 

      } 

      @Override 
      public boolean getEnableSessionCreation() { 
       return false; 
      } 

      @Override 
      public String[] getEnabledCipherSuites() { 
       return null; 
      } 

      @Override 
      public String[] getEnabledProtocols() { 
       return null; 
      } 

      @Override 
      public boolean getNeedClientAuth(){ 
       return false; 
      } 

      @Override 
      public SSLSession getSession() { 
       return new SSLSession() { 

        @Override 
        public int getApplicationBufferSize() { 
         return 0; 
        } 

        @Override 
        public String getCipherSuite() { 
         throw new UnsupportedOperationException(); 
        } 

        @Override 
        public long getCreationTime() { 
         throw new UnsupportedOperationException(); 
        } 

        @Override 
        public byte[] getId() { 
         throw new UnsupportedOperationException(); 
        } 

        @Override 
        public long getLastAccessedTime() { 
         throw new UnsupportedOperationException(); 
        } 

        @Override 
        public java.security.cert.Certificate[] getLocalCertificates() { 
         throw new UnsupportedOperationException(); 
        } 

        @Override 
        public Principal getLocalPrincipal() { 
         throw new UnsupportedOperationException(); 
        } 

        @Override 
        public int getPacketBufferSize() { 
         throw new UnsupportedOperationException(); 
        } 

        @Override 
        public X509Certificate[] getPeerCertificateChain() 
          throws SSLPeerUnverifiedException { 
         return null; 
        } 

        @Override 
        public java.security.cert.Certificate[] getPeerCertificates()throws SSLPeerUnverifiedException { 
         return peertCerts; 
        } 

        @Override 
        public String getPeerHost() { 
         throw new UnsupportedOperationException(); 
        } 

        @Override 
        public int getPeerPort() { 
         return 0; 
        } 

        @Override 
        public Principal getPeerPrincipal() throws SSLPeerUnverifiedException { 
         return null; 
         //throw new UnsupportedOperationException(); 
        } 

        @Override 
        public String getProtocol() { 
         throw new UnsupportedOperationException(); 
        } 

        @Override 
        public SSLSessionContext getSessionContext() { 
         throw new UnsupportedOperationException(); 
        } 

        @Override 
        public Object getValue(String arg0) { 
         throw new UnsupportedOperationException(); 
        } 

        @Override 
        public String[] getValueNames() { 
         throw new UnsupportedOperationException(); 
        } 

        @Override 
        public void invalidate() { 
         throw new UnsupportedOperationException(); 
        } 

        @Override 
        public boolean isValid() { 
         throw new UnsupportedOperationException(); 
        } 

        @Override 
        public void putValue(String arg0, Object arg1) { 
         throw new UnsupportedOperationException(); 
        } 

        @Override 
        public void removeValue(String arg0) { 
         throw new UnsupportedOperationException(); 
        } 

       }; 
      } 


      @Override 
      public String[] getSupportedProtocols() { 
       return null; 
      } 

      @Override 
      public boolean getUseClientMode() { 
       return false; 
      } 

      @Override 
      public boolean getWantClientAuth() { 
       return false; 
      } 

      @Override 
      public void removeHandshakeCompletedListener(HandshakeCompletedListener arg0) { 

      } 

      @Override 
      public void setEnableSessionCreation(boolean arg0) { 

      } 

      @Override 
      public void setEnabledCipherSuites(String[] arg0) { 

      } 

      @Override 
      public void setEnabledProtocols(String[] arg0) { 

      } 

      @Override 
      public void setNeedClientAuth(boolean arg0) { 

      } 

      @Override 
      public void setUseClientMode(boolean arg0) { 

      } 

      @Override 
      public void setWantClientAuth(boolean arg0) { 

      } 

      @Override 
      public String[] getSupportedCipherSuites() { 
       return null; 
      } 
      @Override 
      public void startHandshake() throws IOException { 

       Log.to("util").info("TSLSocketConnectionFactory:startHandshake()"); 
       tlsClientProtocol.connect(new DefaultTlsClient() { 
        @SuppressWarnings("unchecked") 
        @Override 
        public Hashtable<Integer, byte[]> getClientExtensions() throws IOException { 
         Hashtable<Integer, byte[]> clientExtensions = super.getClientExtensions(); 
         if (clientExtensions == null) { 
          clientExtensions = new Hashtable<Integer, byte[]>(); 
         } 

         //Add host_name 
         byte[] host_name = host.getBytes(); 

         final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
         final DataOutputStream dos = new DataOutputStream(baos); 
         dos.writeShort(host_name.length + 3); 
         dos.writeByte(0); // 
         dos.writeShort(host_name.length); 
         dos.write(host_name); 
         dos.close(); 
         clientExtensions.put(ExtensionType.server_name, baos.toByteArray()); 
         return clientExtensions; 
        } 

        @Override 
        public TlsAuthentication getAuthentication() 
          throws IOException { 
         return new TlsAuthentication() { 

          @Override 
          public void notifyServerCertificate(Certificate serverCertificate) throws IOException { 

           try { 
            KeyStore ks = _loadKeyStore(); 
            Log.to("util").info(">>>>>>>> KeyStore : "+ks.size()); 

            CertificateFactory cf = CertificateFactory.getInstance("X.509"); 
            List<java.security.cert.Certificate> certs = new LinkedList<java.security.cert.Certificate>(); 
            boolean trustedCertificate = false; 
            for (org.bouncycastle.asn1.x509.Certificate c : serverCertificate.getCertificateList()) { 
             java.security.cert.Certificate cert = cf.generateCertificate(new ByteArrayInputStream(c.getEncoded())); 
             certs.add(cert); 

             String alias = ks.getCertificateAlias(cert); 
             if(alias != null) { 
              Log.to("util").info(">>> Trusted cert\n" + c.getSubject().toString()); 
              if (cert instanceof java.security.cert.X509Certificate) { 
               try { 
                ((java.security.cert.X509Certificate) cert).checkValidity(); 
                trustedCertificate = true; 
                Log.to("util").info("Certificate is active for current date\n"+cert); 
               } catch(CertificateExpiredException cee) { 
                R01FLog.to("r01f.util").info("Certificate is expired..."); 
               } 
              } 
             } else { 
             Log.to("util").info(">>> Unknown cert " + c.getSubject().toString()); 
              Log.to("util").fine(""+cert); 
             } 

            } 
            if (!trustedCertificate) { 
             throw new CertificateException("Unknown cert " + serverCertificate); 
            } 
            peertCerts = certs.toArray(new java.security.cert.Certificate[0]); 
           } catch (Exception ex) { 
            ex.printStackTrace(); 
            throw new IOException(ex); 
           } 

          } 

          @Override 
          public TlsCredentials getClientCredentials(CertificateRequest arg0) 
            throws IOException { 
           return null; 
          } 

          /** 
          * Private method to load keyStore with system or default properties. 
          * @return 
          * @throws Exception 
          */ 
          private KeyStore _loadKeyStore() throws Exception { 
           FileInputStream trustStoreFis = null; 
           try { 
            String sysTrustStore = null; 
            File trustStoreFile = null; 

            KeyStore localKeyStore = null; 

            sysTrustStore = System.getProperty("javax.net.ssl.trustStore"); 
            String javaHome; 
            if (!"NONE".equals(sysTrustStore)) { 
             if (sysTrustStore != null) { 
              trustStoreFile = new File(sysTrustStore); 
              trustStoreFis = _getFileInputStream(trustStoreFile); 
             } else { 
              javaHome = System.getProperty("java.home"); 
              trustStoreFile = new File(javaHome + File.separator + "lib" + File.separator + "security" + File.separator + "jssecacerts"); 

              if ((trustStoreFis = _getFileInputStream(trustStoreFile)) == null) { 
               trustStoreFile = new File(javaHome + File.separator + "lib" + File.separator + "security" + File.separator + "cacerts"); 
               trustStoreFis = _getFileInputStream(trustStoreFile); 
              } 
             } 

             if (trustStoreFis != null) { 
              sysTrustStore = trustStoreFile.getPath(); 
             } else { 
              sysTrustStore = "No File Available, using empty keystore."; 
             } 
            } 

            String trustStoreType = System.getProperty("javax.net.ssl.trustStoreType")!=null?System.getProperty("javax.net.ssl.trustStoreType"):KeyStore.getDefaultType(); 
            String trustStoreProvider = System.getProperty("javax.net.ssl.trustStoreProvider")!=null?System.getProperty("javax.net.ssl.trustStoreProvider"):""; 

            if (trustStoreType.length() != 0) { 
             if (trustStoreProvider.length() == 0) { 
              localKeyStore = KeyStore.getInstance(trustStoreType); 
             } else { 
              localKeyStore = KeyStore.getInstance(trustStoreType, trustStoreProvider); 
             } 

             char[] keyStorePass = null; 
             String str5 = System.getProperty("javax.net.ssl.trustStorePassword")!=null?System.getProperty("javax.net.ssl.trustStorePassword"):""; 

             if (str5.length() != 0) { 
              keyStorePass = str5.toCharArray(); 
             } 

             localKeyStore.load(trustStoreFis, (char[]) keyStorePass); 

             if (keyStorePass != null) { 
              for (int i = 0; i < keyStorePass.length; i++) { 
               keyStorePass[i] = 0; 
              } 
             } 
            } 
            return (KeyStore)localKeyStore; 
           } finally { 
            if (trustStoreFis != null) { 
             trustStoreFis.close(); 
            } 
           } 
          } 

          private FileInputStream _getFileInputStream(File paramFile) throws Exception { 
           if (paramFile.exists()) { 
            return new FileInputStream(paramFile); 
           } 
           return null; 
          } 

         }; 

        } 

       }); 

      } 

     };//Socket 

    } 

} 
+0

Возможно, сервер TLS использует расширение сервера, чтобы выразить его код Eliptic Curve, который не поддерживается клиентом? Это описано в [rfc4492] (https://www.ietf.org/rfc/rfc4492.txt) в разделе 5. –

+0

Теоретически поставщики BC поддерживают удлинения эллиптических кривых ... – Azimuts

+1

'TlsECCUtils.readSupportedEllipticCurvesExtension' вызывается в 'AbstractTlsClient' для определения поддерживаемых расширений. Похоже, что серверы, о которых идет речь, делают вещи, которые еще не поддерживаются Bouncycastle. –

ответ

3

Если вы посмотрите на RFC 4492 5.2, вы увидите, что сервер может послать «ec_point_formats» расширение, но только должен сделать это «, когда переговоры о ECC шифровой набор ". Если вы хотите TLSClient просто игнорировать дополнительное расширение вместо повышения исключения, я предлагаю первостепенную TlsClient.allowUnexpectedServerExtension (...), чтобы позволить ec_point_formats таким же образом, реализация по умолчанию позволяет elliptic_curves:

protected boolean allowUnexpectedServerExtension(Integer extensionType, byte[] extensionData) 
    throws IOException 
{ 
    switch (extensionType.intValue()) 
    { 
    case ExtensionType.ec_point_formats: 
     /* 
     * Exception added based on field reports that some servers send Supported 
     * Point Format Extension even when not negotiating an ECC cipher suite. 
     * If present, we still require that it is a valid ECPointFormatList. 
     */ 
     TlsECCUtils.readSupportedPointFormatsExtension(extensionData); 
     return true; 
    default: 
     return super.allowUnexpectedServerExtension(extensionType, extensionData); 
    } 
} 

Если это широко распространенной проблемой, мы могли бы рассмотреть вопрос о добавлении этого случая к реализации по умолчанию.

Для ведения журнала существуют методы (TLSPeer) notifyAlertRaised и notifyAlertReceived, которые можно переопределить при реализации TLSClient.

+0

... Я думаю, что эти методы нельзя переопределить для защиты .... – Azimuts

+0

Вы попробовали? Фактически вы можете переопределить защищенный метод в подклассе. Код, который вы указываете, создает (анонимный) подкласс DefaultTlsClient, здесь вы хотите переопределить allowUnexpectedServerExtension(). –

+0

Он отлично работает! Спасибо !!) – Azimuts

Смежные вопросы