- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在尝试使用本地证书颁发机构,但我不断收到“ECDH 服务器 key 交换消息上的无效签名”错误。提前为这个问题的复杂性道歉。您可以通过以下方式从 github 获取完整的源代码:
git clone git://github.com/ClarkHobbie/ssltest.git
然后编译
mvn package
然后运行它
java -cp target\ssl-test-1.0-SNAPSHOT.jar;lib\netty-all-4.1.6.Final.jar SSLTest server
在不同的窗口使用
java -cp target\ssl-test-1.0-SNAPSHOT.jar;lib\netty-all-4.1.6.Final.jar SSLTest client
当我尝试运行该程序时,我会看到提示符(例如“localhost:6789>”),然后我会尝试“测试”之类的东西,然后我收到错误。
如果我不全部使用 netty(请参阅第二个代码块),它似乎可以工作。
这是完整的堆栈跟踪:
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
这是 netty 版本(抛出异常):
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());
}
}
}
我在 Stack Overflow 上达到了字符数限制 (30,000),因此您需要转到 GitHub 才能查看非 netty 版本。
https://github.com/ClarkHobbie/ssltest2
至于为什么我完全使用加密,以及为什么我特别使用本地证书颁发机构,我正在开发一个位于 Web 服务前面并为它们记录消息的工具。该工具是集群的,因此任何消息(POST/PUT/DELETE)都可以通过 Internet 传输。为了识别节点和保护内容,使用了加密。客户端可以为其所有节点获取 CERT(昂贵、缓慢且不方便)或使用本地证书颁发机构。参见 https://ltsllc.blogspot.com/2017/02/the-invalid-signature-problem.html了解更多详情。
最佳答案
如果您遇到此问题,请尝试使用核心 Java 和 Mina。如果您的项目使用其中之一,请使用其中之一。
我是第一个说这不是理想解决方案的人。本来不错的事情应该是“哦,使用选项 xyz,它会起作用”,但是在我为这个问题苦苦思索了两周之后,接着是 Stack Overflow 上的一周,然后是一周的工作与 Netty 的人们一起,我准备使用其他东西。
我在 GitHub 上提供了三个测试程序(ssltest、ssltest2 和 ssltest3),并指出虽然该程序不适用于 Netty,但它确实适用于核心 Java 或 Mina。最终结果仍然是“这不是错误。”
在这一点上,我的项目似乎可以与 Mina 一起使用,所以我将继续使用它。对于其他人:如果你没有遇到这个问题,那么一定要使用 Netty。如果您确实遇到了这个问题,那么我建议您尝试使用其他方法,如果可行,就使用它。
关于java - ECDH 服务器 key 交换消息上的签名无效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42445115/
我正在编写一个具有以下签名的 Java 方法。 void Logger(Method method, Object[] args); 如果一个方法(例如 ABC() )调用此方法 Logger,它应该
我是 Java 新手。 我的问题是我的 Java 程序找不到我试图用作的图像文件一个 JButton。 (目前这段代码什么也没做,因为我只是得到了想要的外观第一的)。这是我的主课 代码: packag
好的,今天我在接受采访,我已经编写 Java 代码多年了。采访中说“Java 垃圾收集是一个棘手的问题,我有几个 friend 一直在努力弄清楚。你在这方面做得怎么样?”。她是想骗我吗?还是我的一生都
我的 friend 给了我一个谜语让我解开。它是这样的: There are 100 people. Each one of them, in his turn, does the following
如果我将使用 Java 5 代码的应用程序编译成字节码,生成的 .class 文件是否能够在 Java 1.4 下运行? 如果后者可以工作并且我正在尝试在我的 Java 1.4 应用程序中使用 Jav
有关于why Java doesn't support unsigned types的问题以及一些关于处理无符号类型的问题。我做了一些搜索,似乎 Scala 也不支持无符号数据类型。限制是Java和S
我只是想知道在一个 java 版本中生成的字节码是否可以在其他 java 版本上运行 最佳答案 通常,字节码无需修改即可在 较新 版本的 Java 上运行。它不会在旧版本上运行,除非您使用特殊参数 (
我有一个关于在命令提示符下执行 java 程序的基本问题。 在某些机器上我们需要指定 -cp 。 (类路径)同时执行java程序 (test为java文件名与.class文件存在于同一目录下) jav
我已经阅读 StackOverflow 有一段时间了,现在我才鼓起勇气提出问题。我今年 20 岁,目前在我的家乡(罗马尼亚克卢日-纳波卡)就读 IT 大学。足以介绍:D。 基本上,我有一家提供簿记应用
我有 public JSONObject parseXML(String xml) { JSONObject jsonObject = XML.toJSONObject(xml); r
我已经在 Java 中实现了带有动态类型的简单解释语言。不幸的是我遇到了以下问题。测试时如下代码: def main() { def ks = Map[[1, 2]].keySet()
一直提示输入 1 到 10 的数字 - 结果应将 st、rd、th 和 nd 添加到数字中。编写一个程序,提示用户输入 1 到 10 之间的任意整数,然后以序数形式显示该整数并附加后缀。 public
我有这个 DownloadFile.java 并按预期下载该文件: import java.io.*; import java.net.URL; public class DownloadFile {
我想在 GUI 上添加延迟。我放置了 2 个 for 循环,然后重新绘制了一个标签,但这 2 个 for 循环一个接一个地执行,并且标签被重新绘制到最后一个。 我能做什么? for(int i=0;
我正在对对象 Student 的列表项进行一些测试,但是我更喜欢在 java 类对象中创建硬编码列表,然后从那里提取数据,而不是连接到数据库并在结果集中选择记录。然而,自从我这样做以来已经很长时间了,
我知道对象创建分为三个部分: 声明 实例化 初始化 classA{} classB extends classA{} classA obj = new classB(1,1); 实例化 它必须使用
我有兴趣使用 GPRS 构建车辆跟踪系统。但是,我有一些问题要问以前做过此操作的人: GPRS 是最好的技术吗?人们意识到任何问题吗? 我计划使用 Java/Java EE - 有更好的技术吗? 如果
我可以通过递归方法反转数组,例如:数组={1,2,3,4,5} 数组结果={5,4,3,2,1}但我的结果是相同的数组,我不知道为什么,请帮助我。 public class Recursion { p
有这样的标准方式吗? 包括 Java源代码-测试代码- Ant 或 Maven联合单元持续集成(可能是巡航控制)ClearCase 版本控制工具部署到应用服务器 最后我希望有一个自动构建和集成环境。
我什至不知道这是否可能,我非常怀疑它是否可能,但如果可以,您能告诉我怎么做吗?我只是想知道如何从打印机打印一些文本。 有什么想法吗? 最佳答案 这里有更简单的事情。 import javax.swin
我是一名优秀的程序员,十分优秀!