TLS 1.2 + Java 1.6 + BouncyCastle

匿名 (未验证) 提交于 2019-12-03 01:23:02

问题:

For supporting HTTPS connections through a Java 1.6 API to remote hosts using TLS 1.2, we have developed a customized TLS SocketConnection factory based on Bouncy Castle Libraries (v. 1.53)

It's very easy to use, just:

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

During testing, I connect different web and remote hosts exposed into SSLabs Tests

90% of the time this works fine! But there are some cases in which we get an annoying error: "Internal TLS error, this could be an attack" . It has been checked that there is no attack. That's a common error based on the treatment of internal BouncyCastle exceptions. I'm trying to find a common pattern to those remote host that fails with little luck.

Updated:

Updating some code for extra information, we get this:

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) 

The extension type i get is this:

ExtensionType:11 ExtensionData:

Acording to ExtensionType class, "ec_point_formats". This causes "UnexpectedServerExtension" --> The "UnexpectedServerExtension" causes a --> TlsFatalAlert: illegal_parameter , and at last this a "Internal TLS error, this could be an attack"

Any advise to log or trace this strange TLS Errors....???? As i say, this code works 90%...but with some remote host i get this errof

The trick consists in overriding startHandShake to use Bouncy's TLSClientProtocol:

  1. Override ClientExtensions to include "host" ExtensionType. Just ExtensionType.server_name ( maybe any more Extension to include?)
  2. Create a TlsAuthentication to include remoteCerts on Socket's peerCertificate .Also optionally check if remote certs are in default keystore (cacerts,etc..)

I share the code of 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 getClientExtensions() throws IOException {                         Hashtable clientExtensions = super.getClientExtensions();                         if (clientExtensions == null) {                             clientExtensions = new Hashtable();                         }                          //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 certs = new LinkedList();                                     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 

回答1:

If you look at RFC 4492 5.2, you'll see that the server CAN send the "ec_point_formats" extension, but is only supposed to do so "when negotiating an ECC cipher suite". If you want TLSClient to just ignore the extra extension instead of raising an exception, I suggest overriding TlsClient.allowUnexpectedServerExtension(...) to allow ec_point_formats in the same way the default implementation allows 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);     } } 

If this is a widespread problem, we might consider adding this case to the default implementation.

For logging, there are the (TLSPeer) methods notifyAlertRaised and notifyAlertReceived that you can override on your TLSClient implementation.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!