为了支持通过Java 1.6 API使用TLS 1.2到远程主机的HTTPS连接,我们基于Bouncy Castle Libraries(v。1.53)开发了定制的TLS SocketConnection工厂。

它非常易于使用,只需:

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

在测试过程中,我连接了暴露在SSLabs Tests中的不同Web和远程主机

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)

我得到的扩展类型是这样的:

扩展类型:11
扩展数据:

根据ExtensionType类“ec_point_formats”。这将导致“UnexpectedServerExtension”->“UnexpectedServerExtension”导致-> TlsFatalAlert:invalid_parameter,最后这是一个“内部TLS错误,这可能是攻击”

任何建议记录或跟踪此奇怪的TLS错误.... ????就像我说的那样,这段代码可以工作90%...但是在某些远程主机上我得到了这个错误

诀窍在于重写startHandShake以使用Bouncy的TLSClientProtocol:
  • 覆盖ClientExtensions以包括“主机” ExtensionType。只是ExtensionType.server_name(也许还有其他扩展要包括?)
  • 创建一个TlsAuthentication以便在Socket的套接字上包含remoteCerts
    peerCertificate。还可以选择检查远程证书是否在
    默认密钥库(证书等)

  • 我共享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
    
        }
    
    }
    

    最佳答案

    如果您查看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);
        }
    }
    

    如果这是一个普遍的问题,我们可以考虑将这种情况添加到默认实现中。

    对于日志记录,您可以在TLSClient实现上覆盖(TLSPeer)方法notifyAlertRaised和notifyAlertReceived。

    07-24 09:30