2017-02-24 6 views
0

Ich versuche, eine lokale Zertifizierungsstelle zu verwenden, und ich erhalte immer wieder den Fehler "Ungültige Signatur beim ECDH-Serverschlüsselaustausch". Entschuldigung im Voraus für die Komplexität dieses Problems. Sie können die kompletten Sourcen von GitHub über erhalten:Ungültige Signatur auf der ECDH-Server-Schlüsselaustauschnachricht

git clone git://github.com/ClarkHobbie/ssltest.git 

Und dann kompilieren es mit

mvn package 

Und es dann mit

java -cp target\ssl-test-1.0-SNAPSHOT.jar;lib\netty-all-4.1.6.Final.jar SSLTest server 

und in einem anderen Fenster Gebrauch laufen

java -cp target\ssl-test-1.0-SNAPSHOT.jar;lib\netty-all-4.1.6.Final.jar SSLTest client 

Wenn ich versuche, das Programm auszuführen, komme ich zur Eingabeaufforderung (wie "localhost: 6789>") und ich versuche etwas wie "test" Dann bekomme ich den Fehler.

Wenn ich netty nicht alle benutze (siehe den zweiten Block des Codes) scheint es zu funktionieren. Hier

ist der komplette Stack-Trace:

io.netty.handler.codec.DecoderException: javax.net.ssl.SSLKeyException: Invalid signature on ECDH server key exchange message 
    at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:442) 
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:248) 
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:373) 
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:359) 
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:351) 
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1334) 
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:373) 
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:359) 
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:926) 
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:129) 
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:651) 
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:574) 
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:488) 
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:450) 
    at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:873) 
    at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:144) 
    at java.lang.Thread.run(Thread.java:745) 
Caused by: javax.net.ssl.SSLKeyException: Invalid signature on ECDH server key exchange message 
    at sun.security.ssl.Handshaker.checkThrown(Handshaker.java:1434) 
    at sun.security.ssl.SSLEngineImpl.checkTaskThrown(SSLEngineImpl.java:535) 
    at sun.security.ssl.SSLEngineImpl.readNetRecord(SSLEngineImpl.java:813) 
    at sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:781) 
    at javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:624) 
    at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1097) 
    at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:968) 
    at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:902) 
    at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:411) 
    ... 16 more 
Caused by: javax.net.ssl.SSLKeyException: Invalid signature on ECDH server key exchange message 
    at sun.security.ssl.HandshakeMessage$ECDH_ServerKeyExchange.<init>(HandshakeMessage.java:1119) 
    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:284) 
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979) 
    at sun.security.ssl.Handshaker$1.run(Handshaker.java:919) 
    at sun.security.ssl.Handshaker$1.run(Handshaker.java:916) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at sun.security.ssl.Handshaker$DelegatedTask.run(Handshaker.java:1369) 
    at io.netty.handler.ssl.SslHandler.runDelegatedTasks(SslHandler.java:1123) 
    at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1008) 
    ... 18 more 

Hier ist die netty Version (das wirft die Ausnahme):

import io.netty.bootstrap.Bootstrap; 
import io.netty.bootstrap.ServerBootstrap; 
import io.netty.buffer.ByteBuf; 
import io.netty.buffer.ByteBufUtil; 
import io.netty.buffer.Unpooled; 
import io.netty.channel.ChannelHandlerContext; 
import io.netty.channel.ChannelInboundHandlerAdapter; 
import io.netty.channel.ChannelInitializer; 
import io.netty.channel.nio.NioEventLoopGroup; 
import io.netty.channel.socket.ServerSocketChannel; 
import io.netty.channel.socket.SocketChannel; 
import io.netty.channel.socket.nio.NioServerSocketChannel; 
import io.netty.channel.socket.nio.NioSocketChannel; 
import io.netty.handler.ssl.SslContext; 
import io.netty.handler.ssl.SslContextBuilder; 
import io.netty.handler.ssl.SslHandler; 

import javax.net.ssl.TrustManagerFactory; 
import java.io.*; 
import java.security.GeneralSecurityException; 
import java.security.KeyStore; 
import java.security.PrivateKey; 
import java.security.cert.Certificate; 
import java.security.cert.X509Certificate; 

/** 
* Created by Clark on 2/27/2017. 
*/ 
public class SSLTest { 
    public static class ServerChannelInitializer extends ChannelInitializer<NioSocketChannel> { 
     private SslContext sslContext; 

     public ServerChannelInitializer (SslContext sslContext) { 
      this.sslContext = sslContext; 
     } 

     public void initChannel (NioSocketChannel serverSocketChannel) { 
      if (null != sslContext) { 
       SslHandler sslHandler = sslContext.newHandler(serverSocketChannel.alloc()); 
       serverSocketChannel.pipeline().addLast(sslHandler); 
      } 

      EchoHandler echoHandler = new EchoHandler(); 
      serverSocketChannel.pipeline().addLast(echoHandler); 
     } 
    } 

    public static class UserInput { 
     private static UserInput ourInstance; 

     private String prompt; 
     private BufferedReader bufferedReader; 

     public static synchronized void initializeClass (String prompt) { 
      if (null == ourInstance) { 
       ourInstance = new UserInput (prompt); 
      } 
     } 

     public static UserInput getInstance() { 
      return ourInstance; 
     } 

     private UserInput (String prompt) { 
      this.prompt = prompt; 

      InputStreamReader inputStreamReader = new InputStreamReader(System.in); 
      this.bufferedReader = new BufferedReader(inputStreamReader); 
     } 

     public String getLine() throws IOException { 
      System.out.print (prompt); 
      return bufferedReader.readLine(); 
     } 
    } 

    public static class ClientInitializer extends ChannelInitializer<SocketChannel> { 
     private SslContext sslContext; 

     public ClientInitializer (SslContext sslContext) { 
      this.sslContext = sslContext; 
     } 

     public void initChannel (SocketChannel socketChannel) { 
      if (null != sslContext) { 
       SslHandler sslHandler = sslContext.newHandler(socketChannel.alloc()); 
       socketChannel.pipeline().addLast(sslHandler); 
      } 

      ClientChannelHandler clientChannelHandler = new ClientChannelHandler(); 
      socketChannel.pipeline().addLast(clientChannelHandler); 
     } 
    } 

    public static class ClientChannelHandler extends ChannelInboundHandlerAdapter { 
     @Override 
     public void channelActive(ChannelHandlerContext ctx) throws Exception { 
      String input = UserInput.getInstance().getLine(); 

      ByteBuf byteBuf = Unpooled.directBuffer(256); 
      ByteBufUtil.writeUtf8(byteBuf, input); 
      ctx.writeAndFlush(byteBuf); 
     } 

     @Override 
     public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 
      ByteBuf byteBuf = (ByteBuf) msg; 
      byte[] buffer = new byte[byteBuf.readableBytes()]; 
      byteBuf.getBytes(0, buffer); 
      String s = new String(buffer); 

      System.out.println (s); 

      s = UserInput.getInstance().getLine(); 
      if (s.equalsIgnoreCase("quit") || s.equalsIgnoreCase("bye")) { 
       System.out.println ("quiting"); 
       System.exit(0); 
      } 

      byteBuf = Unpooled.directBuffer(256); 
      ByteBufUtil.writeUtf8(byteBuf, s); 
      ctx.writeAndFlush(byteBuf); 
     } 

     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 
      cause.printStackTrace(); 
      ctx.close(); 
     } 
    } 

    public static class EchoHandler extends ChannelInboundHandlerAdapter { 
     @Override 
     public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 
      ByteBuf byteBuf = (ByteBuf) msg; 
      byte[] buffer = new byte[byteBuf.readableBytes()]; 
      byteBuf.getBytes(0, buffer); 
      String s = new String(buffer); 

      System.out.println("got " + s); 

      ctx.writeAndFlush(msg); 
     } 
    } 

    public static class CommandLine { 
     private String[] argv; 
     private int argIndex = 0; 
     private String mode = "server"; 
     private boolean useTls = true; 
     private String host = "localhost"; 
     private int port = 6789; 

     public String[] getArgv() { 
      return argv; 
     } 

     public String getArg() { 
      if (argIndex >= argv.length) 
       return null; 

      return argv[argIndex]; 
     } 

     public void advance() { 
      argIndex++; 
     } 

     public String getMode() { 
      return mode; 
     } 

     public void setMode (String mode) { 
      this.mode = mode; 
     } 

     public boolean useTls() { 
      return useTls; 
     } 

     public void setUseTls (boolean useTls) { 
      this.useTls = useTls; 
     } 

     public String getHost() { 
      return host; 
     } 

     public void setHost (String host) { 
      this.host = host; 
     } 

     public int getPort() { 
      return port; 
     } 

     public void setPort (int port) { 
      this.port = port; 
     } 

     public CommandLine (String[] argv) { 
      this.argv = argv; 
      parse(); 
     } 

     public void parse() { 
      if (argv.length < 1) 
       return; 

      if (null != getArg() && getArg().equalsIgnoreCase("nossl")) { 
       System.out.println ("Plaintext mode"); 
       setUseTls(false); 
       advance(); 
      } 

      if (null != getArg()) { 
       setMode(getArg()); 
       advance(); 
      } 

      if (null != getArg()) { 
       setHost(getArg()); 
       advance(); 
      } 

      if (null != getArg()) { 
       int temp = Integer.parseInt(getArg()); 
       setPort(temp); 
       advance(); 
      } 
     } 
    } 

    private CommandLine commandLine; 

    public CommandLine getCommandLine() { 
     return commandLine; 
    } 

    public SSLTest (CommandLine commandLine) { 
     this.commandLine = commandLine; 
    } 

    public static void closeIgnoreExceptions (Reader reader) 
    { 
     if (null != reader) { 
      try { 
       reader.close(); 
      } catch (IOException e) {} 
     } 
    } 

    public static void closeIgnoreExceptions (InputStream inputStream) { 
     if (null != inputStream) { 
      try { 
       inputStream.close(); 
      } catch (IOException e) {} 
     } 
    } 

    public static void closeIfNonNull (PrintWriter printWriter) { 
     if (null != printWriter) { 
      printWriter.close(); 
     } 
    } 

    public static KeyStore getKeyStore (String filename, String password) { 
     KeyStore keyStore = null; 
     FileInputStream fileInputStream = null; 

     try { 
      fileInputStream = new FileInputStream(filename); 
      keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); 
      keyStore.load (fileInputStream, password.toCharArray()); 
     } catch (Exception e) { 
      e.printStackTrace(); 
      System.exit(1); 
     } finally { 
      closeIgnoreExceptions(fileInputStream); 
     } 

     return keyStore; 
    } 

    public static PrivateKey getPrivateKey (String filename, String password, String alias) { 
     PrivateKey privateKey = null; 
     FileInputStream fileInputStream = null; 

     try { 
      KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); 
      fileInputStream = new FileInputStream(filename); 
      keyStore.load(fileInputStream, password.toCharArray()); 
      privateKey = (PrivateKey) keyStore.getKey(alias, password.toCharArray()); 
     } catch (Exception e) { 
      e.printStackTrace(); 
      System.exit(1); 
     } 

     return privateKey; 
    } 


    public void server() { 
     try { 
      SslContext sslContext = null; 

      if (getCommandLine().useTls()) { 
       String trustStoreFilename = "truststore"; 
       String trustStorePassword = "whatever"; 
       String trustStoreAlias = "ca"; 

       String keyStoreFilename = "serverkeystore"; 
       String keyStorePassword = "whatever"; 
       String keyStoreAlias = "server"; 

       X509Certificate certificate = getCertificate(trustStoreFilename, trustStorePassword, trustStoreAlias); 
       PrivateKey privateKey = getPrivateKey(keyStoreFilename, keyStorePassword, keyStoreAlias); 
       sslContext = SslContextBuilder 
         .forServer(privateKey, certificate) 
         .build(); 
      } 

      ServerChannelInitializer serverChannelInitializer = new ServerChannelInitializer(sslContext); 

      NioEventLoopGroup workerGroup = new NioEventLoopGroup(); 
      NioEventLoopGroup bossGroup = new NioEventLoopGroup(); 

      ServerBootstrap serverBootstrap = new ServerBootstrap(); 
      serverBootstrap.childHandler(serverChannelInitializer); 
      serverBootstrap.group(bossGroup, workerGroup); 
      serverBootstrap.channel(NioServerSocketChannel.class); 

      System.out.println ("listening on port " + getCommandLine().getPort()); 

      serverBootstrap.bind(getCommandLine().getPort()).sync(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
      System.exit(1); 
     } 
    } 

    public static X509Certificate getCertificate (String filename, String password, String alias) { 
     KeyStore keyStore = null; 
     FileInputStream fileInputStream = null; 
     Certificate certificate = null; 

     try { 
      fileInputStream = new FileInputStream(filename); 
      keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); 
      keyStore.load(fileInputStream, password.toCharArray()); 
      certificate = keyStore.getCertificate(alias); 
     } catch (Exception e) { 
      e.printStackTrace(); 
      System.exit(1); 
     } 

     return (X509Certificate) certificate; 
    } 

    public static TrustManagerFactory getTrustManagerFactory (String filename, String password) { 
     TrustManagerFactory trustManagerFactory = null; 

     try { 
      KeyStore keyStore = getKeyStore(filename, password); 
      trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 
      trustManagerFactory.init(keyStore); 
     } catch (GeneralSecurityException e) { 
      e.printStackTrace(); 
      System.exit(1); 
     } 

     return trustManagerFactory; 
    } 

    public void client() { 
     try { 
      String trustStoreFilename = "truststore"; 
      String trustStorePassword = "whatever"; 

      SslContext sslContext = null; 

      if (getCommandLine().useTls()) { 
       TrustManagerFactory trustManagerFactory = getTrustManagerFactory(trustStoreFilename, trustStorePassword); 
       sslContext = SslContextBuilder 
         .forClient() 
         .trustManager(trustManagerFactory) 
         .build(); 
      } 

      NioEventLoopGroup nioEventLoopGroup = new NioEventLoopGroup(); 

      Bootstrap clientBootstrap = new Bootstrap(); 
      clientBootstrap.channel(NioSocketChannel.class); 
      clientBootstrap.group(nioEventLoopGroup); 
      clientBootstrap.handler(new ClientInitializer(sslContext)); 
      clientBootstrap.connect(getCommandLine().getHost(), getCommandLine().getPort()); 
     } catch (Exception e) { 
      e.printStackTrace(); 
      System.exit(1); 
     } 
    } 

    public static void main (String[] argv) { 
     CommandLine commandLine = new CommandLine(argv); 
     SSLTest sslTest = new SSLTest(commandLine); 

     String prompt = commandLine.getHost() + ":" + commandLine.getPort() + "> "; 
     UserInput.initializeClass(prompt); 

     if (commandLine.getMode().equalsIgnoreCase("server")) 
      sslTest.server(); 
     else if (commandLine.getMode().equalsIgnoreCase("client")) 
      sslTest.client(); 
     else { 
      System.err.println ("unknown mode: " + commandLine.getMode()); 
     } 
    } 
} 

Ich schlug die Zeichenbeschränkung (30.000) auf Stack-Überlauf, so dass Sie muss zu GitHub gehen, um die Nicht-Netty-Version zu sehen.

https://github.com/ClarkHobbie/ssltest2

Wie, warum ich Verschlüsselung überhaupt benutze und warum ich insbesondere lokale Zertifizierungsstellen verwende ich ein Werkzeug bin zu entwickeln, die vor Web-Services sitzt und zeichnet Nachrichten für sie. Das Tool ist gruppiert, sodass alle Nachrichten (POST/PUT/DELETE) über das Internet gehen können. Um Knoten zu identifizieren und Inhalte zu schützen, wird Verschlüsselung verwendet. Clients könnten entweder CERTs für alle ihre Knoten erhalten (teuer, langsam und unbequem) oder eine lokale Zertifizierungsstelle verwenden. Weitere Details finden Sie unter https://ltsllc.blogspot.com/2017/02/the-invalid-signature-problem.html.

+0

Um nach Stimmen zu fragen ist hier ein Nein, und wird möglicherweise zu Downvotes führen, also habe ich diesen Satz entfernt. Außerdem haben Sie keinen Code zur Verfügung gestellt, sodass Ihnen wahrscheinlich niemand helfen kann.Der Stack-Trace scheint keine Frames in Ihrem Code zu enthalten, daher ist nicht klar, was passiert. Ich denke, Sie müssen das Problem etwas eingrenzen. –

+0

Jim danke für deine Hinweise und Vorschläge - Ich habe die Quelldateien zu der Frage hinzugefügt. Ich habe auch versucht, die Eigenschaften javax.net.ssl.trustStore und javax.net.ssl.trustStorePassword zu setzen. Das System verwendet sie (ich bekomme eine FileNotFoundException, wenn ich eine Datei verwende, die nicht existiert), aber gibt mir immer noch die ungültige Signatur Ausnahme. –

+0

Ich habe ein "no netty" Programm hinzugefügt, das zu funktionieren scheint. –

Antwort

0

Wenn dieses Problem auftritt, versuchen Sie es mit Core Java und Mina. Wenn Ihr Projekt mit einem dieser Projekte arbeitet, verwenden Sie eines davon.

Ich bin der Erste, der sagt, dass dies keine ideale Lösung ist. Was schön gewesen wäre, wäre etwas nach dem Motto "Oh, nutze Option xyz und es wird funktionieren", aber nach zwei Wochen, in denen ich meinen Kopf gegen dieses Problem schlug, folgte eine Woche auf Stack Overflow, gefolgt von einer Woche Arbeit Mit den Leuten von Netty bin ich bereit, etwas anderes zu benutzen.

Ich habe drei Testprogramme auf GitHub (ssltest, ssltest2 und ssltest3) zur Verfügung gestellt und festgestellt, dass, während das Programm nicht mit Netty arbeitete, es mit Core Java oder Mina funktioniert. Das Endergebnis war immer noch "Das ist kein Fehler."

An diesem Punkt scheint mein Projekt mit Mina zu arbeiten, also gehe ich damit um. Für andere: Wenn Sie nicht auf dieses Problem stoßen, dann verwenden Sie netty. Wenn Sie dieses Problem haben, würde ich vorschlagen, es mit etwas anderem zu versuchen, und wenn das funktioniert, es zu benutzen.

Verwandte Themen