title: TLS 1.2 + Java 1.6 + BouncyCastle
body: <p>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)</p>
  
  <p>It's very easy to use, just: </p>
  
  <pre><code>        String httpsURL =  xxxxxxxxxx
          URL myurl = new URL(httpsURL);      
          HttpsURLConnection  con = (HttpsURLConnection )myurl.openConnection();
          con.setSSLSocketFactory(new TSLSocketConnectionFactory());   
          InputStream ins = con.getInputStream();
  </code></pre>
  
  <p>During testing, I connect different web and remote hosts exposed into <a href="https://www.ssllabs.com/ssltest/index.html" rel="noreferrer">SSLabs Tests</a></p>
  
  <p>90% of the time this works fine! But there are some cases in which we get an annoying error: <strong>"Internal TLS error, this could be an attack"</strong> . It has been checked that there is no attack. That's a common error based on the treatment of internal BouncyCastle exceptions. <strong>I'm trying to find a common pattern to those remote host that fails with little luck.</strong></p>
  
  <p><strong>Updated:</strong> </p>
  
  <p>Updating some code for extra information, we get this:</p>
  
  <pre><code>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)
  </code></pre>
  
  <p>The extension type i get is this: </p>
  
  <p>ExtensionType:11
  ExtensionData:</p>
  
  <p>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"</p>
  
  <p>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</p>
  
  <p>The trick consists in overriding startHandShake to use Bouncy's TLSClientProtocol:</p>
  
  <ol>
  <li>Override ClientExtensions to include "host" ExtensionType. Just ExtensionType.server_name ( maybe any more Extension to include?)</li>
  <li>Create a   TlsAuthentication to include remoteCerts on Socket's
  peerCertificate    .Also optionally check if remote certs are in
  default keystore    (cacerts,etc..)</li>
  </ol>
  
  <p>I share the code of TLSSocketConnectionFactory: </p>
  
  <pre><code>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&lt;Integer, byte[]&gt; getClientExtensions() throws IOException {
                          Hashtable&lt;Integer, byte[]&gt; clientExtensions = super.getClientExtensions();
                          if (clientExtensions == null) {
                              clientExtensions = new Hashtable&lt;Integer, byte[]&gt;();
                          }
  
                          //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("&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt; KeyStore : "+ks.size());
  
                                      CertificateFactory cf = CertificateFactory.getInstance("X.509");
                                      List&lt;java.security.cert.Certificate&gt; certs = new LinkedList&lt;java.security.cert.Certificate&gt;();
                                      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("&gt;&gt;&gt; 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("&gt;&gt;&gt; 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 &lt; 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
  
      }
  
  }
  </code></pre>