in netty-handler-ssl, drop conscrypt because of https://github.com/google/conscrypt/issues/838, move bouncycastle to separate subproject

This commit is contained in:
Jörg Prante 2024-01-13 23:04:10 +01:00
parent 3d532a821f
commit 07c6dd718a
90 changed files with 1138 additions and 1916 deletions

2
.gitignore vendored
View file

@ -12,5 +12,3 @@
.DS_Store
*.iml
*~
*.key
*.crt

View file

@ -11,6 +11,8 @@ module org.xbib.io.netty.channel {
exports io.netty.channel.oio;
exports io.netty.channel.pool;
exports io.netty.channel.socket;
exports io.netty.channel.socket.nio;
exports io.netty.channel.socket.oio;
uses ChannelInitializerExtension;
requires org.xbib.io.netty.buffer;
requires org.xbib.io.netty.resolver;

View file

@ -3,6 +3,7 @@ dependencies {
testImplementation testLibs.gson
testImplementation testLibs.assertj
testImplementation testLibs.mockito.core
testImplementation project(':netty-handler-ssl-bouncycastle')
testRuntimeOnly project(path: ':netty-tcnative-boringssl-static', configuration: osdetector.classifier)
testRuntimeOnly libs.brotli4j.native."${osdetector.os}"."${osdetector.arch.replace('_','')}"
}

View file

@ -42,7 +42,7 @@ import io.netty.handler.ssl.SslHandshakeCompletionEvent;
import io.netty.handler.ssl.SslProvider;
import io.netty.handler.ssl.SupportedCipherSuiteFilter;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import io.netty.handler.ssl.bouncycastle.SelfSignedCertificate;
import io.netty.util.CharsetUtil;
import io.netty.util.NetUtil;
import io.netty.util.ReferenceCountUtil;

View file

@ -3,4 +3,5 @@ dependencies {
api project(':netty-handler-codec-quic')
testImplementation testLibs.assertj
testImplementation testLibs.mockito.core
testImplementation project(':netty-handler-ssl-bouncycastle')
}

View file

@ -54,7 +54,7 @@ import io.netty.handler.codec.http.HttpUtil;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.LastHttpContent;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import io.netty.handler.ssl.bouncycastle.SelfSignedCertificate;
import io.netty.handler.codec.quic.InsecureQuicTokenHandler;
import io.netty.handler.codec.quic.QuicChannel;
import io.netty.handler.codec.quic.QuicSslContextBuilder;

View file

@ -23,7 +23,7 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import io.netty.handler.ssl.bouncycastle.SelfSignedCertificate;
import io.netty.handler.codec.quic.InsecureQuicTokenHandler;
import io.netty.handler.codec.quic.QuicChannel;
import io.netty.handler.codec.quic.QuicSslContext;

View file

@ -23,7 +23,7 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import io.netty.handler.ssl.bouncycastle.SelfSignedCertificate;
import io.netty.handler.codec.http3.DefaultHttp3DataFrame;
import io.netty.handler.codec.http3.DefaultHttp3HeadersFrame;
import io.netty.handler.codec.http3.Http3;

View file

@ -0,0 +1,18 @@
-----BEGIN CERTIFICATE-----
MIIC7TCCAdUCFDuGBhl3l5Z++VCLkvaav4yteBonMA0GCSqGSIb3DQEBCwUAMEUx
CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRl
cm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMjAwMzIzMTYwNzU0WhcNNDcwODA5MTYw
NzU0WjAhMQswCQYDVQQGEwJHQjESMBAGA1UEAwwJcXVpYy50ZWNoMIIBIjANBgkq
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz5bOL7LD9kiIagcVrZqZ13ZcR0KhMuzs
brqULbZKyqC+uBRgINxYJ7LPnJ4LPYuCt/nAaQ7CLXfKgzAMFu8eIK6UEvZA6+7b
20E4rvOpPbTB/T4JbYZNQKyM9AEwr6j0P6vFgrWT7aBzhkmiqEe5vv/7ZOEGb+Ab
+cvMeszfBbk93nyzKdNaUuh95x7/p0Ow315np2PRuoT0QQnA9zE/9eZ3Jah3cNZn
NuQ6BDHlkegzTV5JhYYblRo/pmt2E9E0ha+NWsRLf3ZJUYhkYR3UqMltEKuLglCO
VWBbPmKd4IZUNIotpKMVQSVb9agNBF49hH9iBhN3fBm7Hp8KBpjJLwIDAQABMA0G
CSqGSIb3DQEBCwUAA4IBAQCo/Rn4spa5XFk0cCoKypP27DxePkGD9rQZk/CY4inV
JV16anZ1pr9yfO61+m3fRKTZq7yxtHRDWxDdROHx9LqV1dXLAmh1ecV9Kn6/796O
EHsOcVB0Lfi9Ili7//oUqlhGNploRuQbgWAXU+Eo1xJRWIXeedhzBSgEOMaQk3Zn
TdYFhP0/Ao/fEdI4VULv1A43ztnZIB2KXWgUQoFT32woL47eWge8LxxVmmH3STtz
nNcGnYxIorCQemDHDzMrvxRWgHxkpFGGqAhkFFyCmhKFPglKwt+yVTx26T8tShID
ISMj0rgVMptmtWKJfzNCvFG52gsuO4w3yGdjgjRRrBDm
-----END CERTIFICATE-----

View file

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDPls4vssP2SIhq
BxWtmpnXdlxHQqEy7OxuupQttkrKoL64FGAg3Fgnss+cngs9i4K3+cBpDsItd8qD
MAwW7x4grpQS9kDr7tvbQTiu86k9tMH9Pglthk1ArIz0ATCvqPQ/q8WCtZPtoHOG
SaKoR7m+//tk4QZv4Bv5y8x6zN8FuT3efLMp01pS6H3nHv+nQ7DfXmenY9G6hPRB
CcD3MT/15nclqHdw1mc25DoEMeWR6DNNXkmFhhuVGj+ma3YT0TSFr41axEt/dklR
iGRhHdSoyW0Qq4uCUI5VYFs+Yp3ghlQ0ii2koxVBJVv1qA0EXj2Ef2IGE3d8Gbse
nwoGmMkvAgMBAAECggEBAMtFkpUmablKgTnBwjqCvs47OlUVK6AgW8x5qwuwC0Cr
ctXyLcc/vJry/1UPdVZIvDHGv+Cf8Qhw2r7nV49FiqzaBmki9aOR+3uRPB4kvr6L
t8Fw8+5pqlAAJu3wFGqN+M44N2mswDPaAAWpKTu7MGmVY+f+aT03qG1MYOiGoISK
gP6DHiinddD38spM2muyCUyFZk9a+aBEfaQzZoU3gc0yB6R/qBOWZ7NIoIUMicku
Zf3L6/06uunyZp+ueR83j1YWbg3JoYKlGAuQtDRF709+MQrim8lKTnfuHiBeZKYZ
GNLSo7lGjrp6ccSyfXmlA36hSfdlrWtZJ4+utZShftECgYEA+NNOFNa1BLfDw3ot
a6L4W6FE45B32bLbnBdg8foyEYrwzHLPFCbws1Z60pNr7NaCHDIMiKVOXvKQa78d
qdWuPUVJ83uVs9GI8tAo00RAvBn6ut9yaaLa8mIv6ZpfU20IgE5sDjB7IBY9tTVd
EDyJcDuKQXzQ48qmEw86wINQMd0CgYEA1ZMdt7yLnpDiYa6M/BuKjp7PWKcRlzVM
BcCEYHA4LJ6xEOH4y9DEx2y5ljwOcXgJhXAfAyGQr7s1xiP/nXurqfmdP8u7bawp
VwuWJ8Vv0ZXITaU0isezG2Dpnseuion3qSraWlmWUlWLVVgKETZmk7cF7VIXa0NT
LFREdObI5HsCgYBUbm8KRyi5Zxm4VNbgtTYM8ZYMmdLxPe2i85PjyAABT+IRncuC
jQwT7n5Swc9XWBpiMuFp5J3JPgmfZgRMwsMS61YClqbfk3Qi4FtaBMjqiu43Rubt
zWL56DNV0xoRlufRkcq8rdq5spJR0L+5aLFCMhHh0taW1QaxZPOMq4IkyQKBgQC3
GetubGzewqPyzuz77ri5URm+jW0dT4ofnE9hRpRCXMK9EJ52TkOGHYZ2cIKJcTno
dpl/27Tpk/ykJJSu9SnVDbVszkOf4OuIPty6uCAHdPxG5Q3ItTCulkVz5QmUqHf1
RlHxB8FCUSilQFdRLmx+03h3X9vID+4soQoXlwxAJQKBgE5SQpN+TG5V+E4zHgNd
6cy6gA5dGDJ0KbsgxJwlKTFA9nIcs2ssBxLY9U4x75EGuqpeVNmq6xwwmPtBs0rp
M3W4zdFrZQ3BneFRW7WbSBbsUSprkJW/p4GXa17GzGUq/MDXlGhNlApP1nknzFvE
xGaH0/H/TZxpLCogVP9npUkj
-----END PRIVATE KEY-----

View file

@ -1,4 +0,0 @@
dependencies {
api project(':netty-handler-codec')
implementation libs.protobuf
}

View file

@ -1,133 +0,0 @@
/*
* Copyright 2015 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.handler.codec.protobuf;
import com.google.protobuf.ExtensionRegistry;
import com.google.protobuf.ExtensionRegistryLite;
import com.google.protobuf.Message;
import com.google.protobuf.MessageLite;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.MessageToMessageDecoder;
import io.netty.util.internal.ObjectUtil;
import java.util.List;
/**
* Decodes a received {@link ByteBuf} into a
* <a href="https://github.com/google/protobuf">Google Protocol Buffers</a>
* {@link Message} and {@link MessageLite}. Please note that this decoder must
* be used with a proper {@link ByteToMessageDecoder} such as {@link ProtobufVarint32FrameDecoder}
* or {@link LengthFieldBasedFrameDecoder} if you are using a stream-based
* transport such as TCP/IP. A typical setup for TCP/IP would be:
* <pre>
* {@link ChannelPipeline} pipeline = ...;
*
* // Decoders
* pipeline.addLast("frameDecoder",
* new {@link LengthFieldBasedFrameDecoder}(1048576, 0, 4, 0, 4));
* pipeline.addLast("protobufDecoder",
* new {@link ProtobufDecoder}(MyMessage.getDefaultInstance()));
*
* // Encoder
* pipeline.addLast("frameEncoder", new {@link LengthFieldPrepender}(4));
* pipeline.addLast("protobufEncoder", new {@link ProtobufEncoder}());
* </pre>
* and then you can use a {@code MyMessage} instead of a {@link ByteBuf}
* as a message:
* <pre>
* void channelRead({@link ChannelHandlerContext} ctx, Object msg) {
* MyMessage req = (MyMessage) msg;
* MyMessage res = MyMessage.newBuilder().setText(
* "Did you say '" + req.getText() + "'?").build();
* ch.write(res);
* }
* </pre>
*/
@Sharable
public class ProtobufDecoder extends MessageToMessageDecoder<ByteBuf> {
private static final boolean HAS_PARSER;
static {
boolean hasParser = false;
try {
// MessageLite.getParserForType() is not available until protobuf 2.5.0.
MessageLite.class.getDeclaredMethod("getParserForType");
hasParser = true;
} catch (Throwable t) {
// Ignore
}
HAS_PARSER = hasParser;
}
private final MessageLite prototype;
private final ExtensionRegistryLite extensionRegistry;
/**
* Creates a new instance.
*/
public ProtobufDecoder(MessageLite prototype) {
this(prototype, null);
}
public ProtobufDecoder(MessageLite prototype, ExtensionRegistry extensionRegistry) {
this(prototype, (ExtensionRegistryLite) extensionRegistry);
}
public ProtobufDecoder(MessageLite prototype, ExtensionRegistryLite extensionRegistry) {
this.prototype = ObjectUtil.checkNotNull(prototype, "prototype").getDefaultInstanceForType();
this.extensionRegistry = extensionRegistry;
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out)
throws Exception {
final byte[] array;
final int offset;
final int length = msg.readableBytes();
if (msg.hasArray()) {
array = msg.array();
offset = msg.arrayOffset() + msg.readerIndex();
} else {
array = ByteBufUtil.getBytes(msg, msg.readerIndex(), length, false);
offset = 0;
}
if (extensionRegistry == null) {
if (HAS_PARSER) {
out.add(prototype.getParserForType().parseFrom(array, offset, length));
} else {
out.add(prototype.newBuilderForType().mergeFrom(array, offset, length).build());
}
} else {
if (HAS_PARSER) {
out.add(prototype.getParserForType().parseFrom(
array, offset, length, extensionRegistry));
} else {
out.add(prototype.newBuilderForType().mergeFrom(
array, offset, length, extensionRegistry).build());
}
}
}
}

View file

@ -1,74 +0,0 @@
/*
* Copyright 2015 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.handler.codec.protobuf;
import com.google.protobuf.Message;
import com.google.protobuf.MessageLite;
import com.google.protobuf.MessageLiteOrBuilder;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.MessageToMessageEncoder;
import java.util.List;
import static io.netty.buffer.Unpooled.*;
/**
* Encodes the requested <a href="https://github.com/google/protobuf">Google
* Protocol Buffers</a> {@link Message} and {@link MessageLite} into a
* {@link ByteBuf}. A typical setup for TCP/IP would be:
* <pre>
* {@link ChannelPipeline} pipeline = ...;
*
* // Decoders
* pipeline.addLast("frameDecoder",
* new {@link LengthFieldBasedFrameDecoder}(1048576, 0, 4, 0, 4));
* pipeline.addLast("protobufDecoder",
* new {@link ProtobufDecoder}(MyMessage.getDefaultInstance()));
*
* // Encoder
* pipeline.addLast("frameEncoder", new {@link LengthFieldPrepender}(4));
* pipeline.addLast("protobufEncoder", new {@link ProtobufEncoder}());
* </pre>
* and then you can use a {@code MyMessage} instead of a {@link ByteBuf}
* as a message:
* <pre>
* void channelRead({@link ChannelHandlerContext} ctx, Object msg) {
* MyMessage req = (MyMessage) msg;
* MyMessage res = MyMessage.newBuilder().setText(
* "Did you say '" + req.getText() + "'?").build();
* ch.write(res);
* }
* </pre>
*/
@Sharable
public class ProtobufEncoder extends MessageToMessageEncoder<MessageLiteOrBuilder> {
@Override
protected void encode(ChannelHandlerContext ctx, MessageLiteOrBuilder msg, List<Object> out)
throws Exception {
if (msg instanceof MessageLite) {
out.add(wrappedBuffer(((MessageLite) msg).toByteArray()));
return;
}
if (msg instanceof MessageLite.Builder) {
out.add(wrappedBuffer(((MessageLite.Builder) msg).build().toByteArray()));
}
}
}

View file

@ -1,119 +0,0 @@
/*
* Copyright 2015 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.handler.codec.protobuf;
import com.google.protobuf.CodedInputStream;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.CorruptedFrameException;
import java.util.List;
/**
* A decoder that splits the received {@link ByteBuf}s dynamically by the
* value of the Google Protocol Buffers
* <a href="https://developers.google.com/protocol-buffers/docs/encoding#varints">Base
* 128 Varints</a> integer length field in the message. For example:
* <pre>
* BEFORE DECODE (302 bytes) AFTER DECODE (300 bytes)
* +--------+---------------+ +---------------+
* | Length | Protobuf Data |----->| Protobuf Data |
* | 0xAC02 | (300 bytes) | | (300 bytes) |
* +--------+---------------+ +---------------+
* </pre>
*
* @see CodedInputStream
*/
public class ProtobufVarint32FrameDecoder extends ByteToMessageDecoder {
// TODO maxFrameLength + safe skip + fail-fast option
// (just like LengthFieldBasedFrameDecoder)
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out)
throws Exception {
in.markReaderIndex();
int preIndex = in.readerIndex();
int length = readRawVarint32(in);
if (preIndex == in.readerIndex()) {
return;
}
if (length < 0) {
throw new CorruptedFrameException("negative length: " + length);
}
if (in.readableBytes() < length) {
in.resetReaderIndex();
} else {
out.add(in.readRetainedSlice(length));
}
}
/**
* Reads variable length 32bit int from buffer
*
* @return decoded int if buffers readerIndex has been forwarded else nonsense value
*/
private static int readRawVarint32(ByteBuf buffer) {
if (!buffer.isReadable()) {
return 0;
}
buffer.markReaderIndex();
byte tmp = buffer.readByte();
if (tmp >= 0) {
return tmp;
} else {
int result = tmp & 127;
if (!buffer.isReadable()) {
buffer.resetReaderIndex();
return 0;
}
if ((tmp = buffer.readByte()) >= 0) {
result |= tmp << 7;
} else {
result |= (tmp & 127) << 7;
if (!buffer.isReadable()) {
buffer.resetReaderIndex();
return 0;
}
if ((tmp = buffer.readByte()) >= 0) {
result |= tmp << 14;
} else {
result |= (tmp & 127) << 14;
if (!buffer.isReadable()) {
buffer.resetReaderIndex();
return 0;
}
if ((tmp = buffer.readByte()) >= 0) {
result |= tmp << 21;
} else {
result |= (tmp & 127) << 21;
if (!buffer.isReadable()) {
buffer.resetReaderIndex();
return 0;
}
result |= (tmp = buffer.readByte()) << 28;
if (tmp < 0) {
throw new CorruptedFrameException("malformed varint.");
}
}
}
}
return result;
}
}
}

View file

@ -1,88 +0,0 @@
/*
* Copyright 2015 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.handler.codec.protobuf;
import com.google.protobuf.CodedOutputStream;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
/**
* An encoder that prepends the Google Protocol Buffers
* <a href="https://developers.google.com/protocol-buffers/docs/encoding?csw=1#varints">Base
* 128 Varints</a> integer length field. For example:
* <pre>
* BEFORE ENCODE (300 bytes) AFTER ENCODE (302 bytes)
* +---------------+ +--------+---------------+
* | Protobuf Data |-------------->| Length | Protobuf Data |
* | (300 bytes) | | 0xAC02 | (300 bytes) |
* +---------------+ +--------+---------------+
* </pre> *
*
* @see CodedOutputStream
*/
@Sharable
public class ProtobufVarint32LengthFieldPrepender extends MessageToByteEncoder<ByteBuf> {
@Override
protected void encode(
ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception {
int bodyLen = msg.readableBytes();
int headerLen = computeRawVarint32Size(bodyLen);
out.ensureWritable(headerLen + bodyLen);
writeRawVarint32(out, bodyLen);
out.writeBytes(msg, msg.readerIndex(), bodyLen);
}
/**
* Writes protobuf varint32 to (@link ByteBuf).
* @param out to be written to
* @param value to be written
*/
static void writeRawVarint32(ByteBuf out, int value) {
while (true) {
if ((value & ~0x7F) == 0) {
out.writeByte(value);
return;
} else {
out.writeByte((value & 0x7F) | 0x80);
value >>>= 7;
}
}
}
/**
* Computes size of protobuf varint32 after encoding.
* @param value which is to be encoded.
* @return size of value encoded as protobuf varint32.
*/
static int computeRawVarint32Size(final int value) {
if ((value & (0xffffffff << 7)) == 0) {
return 1;
}
if ((value & (0xffffffff << 14)) == 0) {
return 2;
}
if ((value & (0xffffffff << 21)) == 0) {
return 3;
}
if ((value & (0xffffffff << 28)) == 0) {
return 4;
}
return 5;
}
}

View file

@ -1,23 +0,0 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
/**
* Encoder and decoder which transform a
* <a href="https://github.com/google/protobuf">Google Protocol Buffers</a>
* {@link com.google.protobuf.Message} into a
* {@link io.netty.buffer.ByteBuf} and vice versa.
*/
package io.netty.handler.codec.protobuf;

View file

@ -1,8 +0,0 @@
module org.xbib.io.netty.handler.codec.protobuf {
exports io.netty.handler.codec.protobuf;
requires org.xbib.io.netty.buffer;
requires org.xbib.io.netty.channel;
requires org.xbib.io.netty.util;
requires org.xbib.io.netty.handler.codec;
requires com.google.protobuf;
}

View file

@ -3,6 +3,7 @@ module org.xbib.io.netty.handler.codec {
exports io.netty.handler.codec.base64;
exports io.netty.handler.codec.bytes;
exports io.netty.handler.codec.json;
exports io.netty.handler.codec.serialization;
exports io.netty.handler.codec.string;
exports io.netty.handler.codec.xml;
requires org.xbib.io.netty.buffer;

View file

@ -0,0 +1,7 @@
dependencies {
api project(':netty-buffer')
api project(':netty-handler-codec')
api project(':netty-handler-ssl')
api project(':netty-util')
implementation libs.bouncycastle
}

View file

@ -13,12 +13,14 @@
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.handler.ssl;
package io.netty.handler.ssl.bouncycastle;
import io.netty.handler.ssl.PrivateKeyProvider;
import io.netty.util.CharsetUtil;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMDecryptorProvider;
import org.bouncycastle.openssl.PEMEncryptedKeyPair;
import org.bouncycastle.openssl.PEMKeyPair;
@ -37,60 +39,16 @@ import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.AccessController;
import java.security.PrivateKey;
import java.security.PrivilegedAction;
import java.security.Provider;
final class BouncyCastlePemReader {
private static final String BC_PROVIDER = "org.bouncycastle.jce.provider.BouncyCastleProvider";
private static final String BC_PEMPARSER = "org.bouncycastle.openssl.PEMParser";
public final class BouncyCastlePemReader implements PrivateKeyProvider {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(BouncyCastlePemReader.class);
private static volatile Throwable unavailabilityCause;
private static volatile Provider bcProvider;
private static volatile boolean attemptedLoading;
private static final Provider bcProvider = new BouncyCastleProvider();
public static boolean hasAttemptedLoading() {
return attemptedLoading;
}
public static boolean isAvailable() {
if (!hasAttemptedLoading()) {
tryLoading();
}
return unavailabilityCause == null;
}
/**
* @return the cause if unavailable. {@code null} if available.
*/
public static Throwable unavailabilityCause() {
return unavailabilityCause;
}
private static void tryLoading() {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
@Override
public Void run() {
try {
ClassLoader classLoader = getClass().getClassLoader();
// Check for bcprov-jdk15on:
Class<Provider> bcProviderClass =
(Class<Provider>) Class.forName(BC_PROVIDER, true, classLoader);
// Check for bcpkix-jdk15on:
Class.forName(BC_PEMPARSER, true, classLoader);
bcProvider = bcProviderClass.getConstructor().newInstance();
logger.debug("Bouncy Castle provider available");
attemptedLoading = true;
} catch (Throwable e) {
logger.debug("Cannot load Bouncy Castle provider", e);
unavailabilityCause = e;
attemptedLoading = true;
}
return null;
}
});
public BouncyCastlePemReader() {
}
/**
@ -101,13 +59,7 @@ final class BouncyCastlePemReader {
* {@code null} if it's not password-protected.
* @return generated {@link PrivateKey}.
*/
public static PrivateKey getPrivateKey(InputStream keyInputStream, String keyPassword) {
if (!isAvailable()) {
if (logger.isDebugEnabled()) {
logger.debug("Bouncy castle provider is unavailable.", unavailabilityCause());
}
return null;
}
public PrivateKey getPrivateKey(InputStream keyInputStream, String keyPassword) {
try {
PEMParser parser = newParser(keyInputStream);
return getPrivateKey(parser, keyPassword);
@ -125,13 +77,7 @@ final class BouncyCastlePemReader {
* {@code null} if it's not password-protected.
* @return generated {@link PrivateKey}.
*/
public static PrivateKey getPrivateKey(File keyFile, String keyPassword) {
if (!isAvailable()) {
if (logger.isDebugEnabled()) {
logger.debug("Bouncy castle provider is unavailable.", unavailabilityCause());
}
return null;
}
public PrivateKey getPrivateKey(File keyFile, String keyPassword) {
try {
PEMParser parser = newParser(keyFile);
return getPrivateKey(parser, keyPassword);
@ -218,6 +164,4 @@ final class BouncyCastlePemReader {
private static PEMParser newParser(InputStream keyInputStream) {
return new PEMParser(new InputStreamReader(keyInputStream, CharsetUtil.US_ASCII));
}
private BouncyCastlePemReader() { }
}

View file

@ -14,7 +14,7 @@
* under the License.
*/
package io.netty.handler.ssl.util;
package io.netty.handler.ssl.bouncycastle;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.cert.X509CertificateHolder;
@ -33,8 +33,6 @@ import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Date;
import static io.netty.handler.ssl.util.SelfSignedCertificate.newSelfSignedCertificate;
/**
* Generates a self-signed certificate using <a href="https://www.bouncycastle.org/">Bouncy Castle</a>.
*/
@ -57,7 +55,7 @@ final class BouncyCastleSelfSignedCertGenerator {
X509Certificate cert = new JcaX509CertificateConverter().setProvider(PROVIDER).getCertificate(certHolder);
cert.verify(keypair.getPublic());
return newSelfSignedCertificate(fqdn, key, cert);
return SelfSignedCertificate.newSelfSignedCertificate(fqdn, key, cert);
}
private BouncyCastleSelfSignedCertGenerator() { }

View file

@ -14,7 +14,7 @@
* under the License.
*/
package io.netty.handler.ssl.util;
package io.netty.handler.ssl.bouncycastle;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;

View file

@ -14,7 +14,7 @@
* under the License.
*/
package io.netty.handler.ssl.util;
package io.netty.handler.ssl.bouncycastle;
import io.netty.util.internal.PlatformDependent;

View file

@ -0,0 +1,13 @@
import io.netty.handler.ssl.PrivateKeyProvider;
import io.netty.handler.ssl.bouncycastle.BouncyCastlePemReader;
module org.xbib.io.netty.handler.ssl.bouncycastle {
exports io.netty.handler.ssl.bouncycastle;
requires org.xbib.io.netty.buffer;
requires org.xbib.io.netty.handler.codec;
requires org.xbib.io.netty.handler.ssl;
requires org.xbib.io.netty.util;
requires org.bouncycastle.pkix;
requires org.bouncycastle.provider;
provides PrivateKeyProvider with BouncyCastlePemReader;
}

View file

@ -0,0 +1 @@
io.netty.handler.ssl.bouncycastle.BouncyCastlePemReader

View file

@ -13,7 +13,7 @@
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.handler.ssl.util;
package io.netty.handler.ssl.bouncycastle;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.function.Executable;

View file

@ -5,11 +5,10 @@ dependencies {
api project(':netty-handler-codec')
api project(':netty-internal-tcnative')
api project(':netty-channel-unix')
implementation libs.bouncycastle
implementation libs.conscrypt
testImplementation testLibs.mockito.core
testImplementation testLibs.assertj
testImplementation project(':netty-handler')
testImplementation project(':netty-handler-ssl-bouncycastle')
testImplementation (testLibs.amazonCorrettoCrypt) {
artifact {
classifier = osdetector.classifier

View file

@ -15,6 +15,9 @@
*/
package io.netty.handler.ssl;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
import java.security.Provider;
import javax.net.ssl.SSLEngine;
/**
@ -22,8 +25,18 @@ import javax.net.ssl.SSLEngine;
*/
final class BouncyCastle {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(BouncyCastle.class);
private static final boolean BOUNCY_CASTLE_ON_CLASSPATH;
private static final String BC_PROVIDER = "org.bouncycastle.jce.provider.BouncyCastleProvider";
private static final String BC_PEMPARSER = "org.bouncycastle.openssl.PEMParser";
private static volatile Throwable unavailabilityCause;
private static volatile boolean attemptedLoading;
static {
boolean bcOnClasspath = false;
try {
@ -38,7 +51,7 @@ final class BouncyCastle {
/**
* Indicates whether or not BouncyCastle is available on the current system.
*/
static boolean isAvailable() {
public static boolean isAvailable() {
return BOUNCY_CASTLE_ON_CLASSPATH;
}
@ -49,6 +62,40 @@ final class BouncyCastle {
return engine.getClass().getPackage().getName().startsWith("org.bouncycastle.jsse.provider");
}
public static boolean isPemParserAvailable() {
if (!hasAttemptedLoading()) {
tryLoading();
}
return unavailabilityCause == null;
}
public static boolean hasAttemptedLoading() {
return attemptedLoading;
}
/**
* @return the cause if unavailable. {@code null} if available.
*/
public static Throwable unavailabilityCause() {
return unavailabilityCause;
}
private static void tryLoading() {
try {
ClassLoader classLoader = BouncyCastle.class.getClassLoader();
// Check for bcprov-jdk15on:
Class<Provider> bcProviderClass = (Class<Provider>) Class.forName(BC_PROVIDER, true, classLoader);
// Check for bcpkix-jdk15on:
Class.forName(BC_PEMPARSER, true, classLoader);
logger.debug("Bouncy Castle provider available");
attemptedLoading = true;
} catch (Throwable e) {
logger.debug("Cannot load Bouncy Castle provider", e);
unavailabilityCause = e;
attemptedLoading = true;
}
}
private BouncyCastle() {
}
}

View file

@ -1,62 +0,0 @@
/*
* Copyright 2021 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.handler.ssl;
import io.netty.util.internal.SuppressJava6Requirement;
import javax.net.ssl.SSLEngine;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
@SuppressJava6Requirement(reason = "Usage guarded by java version check")
final class BouncyCastleAlpnSslEngine extends JdkAlpnSslEngine {
BouncyCastleAlpnSslEngine(SSLEngine engine,
@SuppressWarnings("deprecation") JdkApplicationProtocolNegotiator applicationNegotiator,
boolean isServer) {
super(engine, applicationNegotiator, isServer,
new BiConsumer<SSLEngine, AlpnSelector>() {
@Override
public void accept(SSLEngine e, AlpnSelector s) {
BouncyCastleAlpnSslUtils.setHandshakeApplicationProtocolSelector(e, s);
}
},
new BiConsumer<SSLEngine, List<String>>() {
@Override
public void accept(SSLEngine e, List<String> p) {
BouncyCastleAlpnSslUtils.setApplicationProtocols(e, p);
}
});
}
public String getApplicationProtocol() {
return BouncyCastleAlpnSslUtils.getApplicationProtocol(getWrappedEngine());
}
public String getHandshakeApplicationProtocol() {
return BouncyCastleAlpnSslUtils.getHandshakeApplicationProtocol(getWrappedEngine());
}
public void setHandshakeApplicationProtocolSelector(BiFunction<SSLEngine, List<String>, String> selector) {
BouncyCastleAlpnSslUtils.setHandshakeApplicationProtocolSelector(getWrappedEngine(), selector);
}
public BiFunction<SSLEngine, List<String>, String> getHandshakeApplicationProtocolSelector() {
return BouncyCastleAlpnSslUtils.getHandshakeApplicationProtocolSelector(getWrappedEngine());
}
}

View file

@ -1,259 +0,0 @@
/*
* Copyright 2021 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.handler.ssl;
import io.netty.util.internal.EmptyArrays;
import io.netty.util.internal.PlatformDependent;
import io.netty.util.internal.SuppressJava6Requirement;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
import java.util.List;
import java.util.function.BiFunction;
import static io.netty.handler.ssl.SslUtils.getSSLContext;
@SuppressJava6Requirement(reason = "Usage guarded by java version check")
final class BouncyCastleAlpnSslUtils {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(BouncyCastleAlpnSslUtils.class);
private static final Method SET_PARAMETERS;
private static final Method GET_PARAMETERS;
private static final Method SET_APPLICATION_PROTOCOLS;
private static final Method GET_APPLICATION_PROTOCOL;
private static final Method GET_HANDSHAKE_APPLICATION_PROTOCOL;
private static final Method SET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR;
private static final Method GET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR;
private static final Class BC_APPLICATION_PROTOCOL_SELECTOR;
private static final Method BC_APPLICATION_PROTOCOL_SELECTOR_SELECT;
static {
Class bcSslEngine;
Method getParameters;
Method setParameters;
Method setApplicationProtocols;
Method getApplicationProtocol;
Method getHandshakeApplicationProtocol;
Method setHandshakeApplicationProtocolSelector;
Method getHandshakeApplicationProtocolSelector;
Method bcApplicationProtocolSelectorSelect;
Class bcApplicationProtocolSelector;
try {
bcSslEngine = Class.forName("org.bouncycastle.jsse.BCSSLEngine");
final Class testBCSslEngine = bcSslEngine;
bcApplicationProtocolSelector =
Class.forName("org.bouncycastle.jsse.BCApplicationProtocolSelector");
final Class testBCApplicationProtocolSelector = bcApplicationProtocolSelector;
bcApplicationProtocolSelectorSelect = AccessController.doPrivileged(
new PrivilegedExceptionAction<Method>() {
@Override
public Method run() throws Exception {
return testBCApplicationProtocolSelector.getMethod("select", Object.class, List.class);
}
});
SSLContext context = getSSLContext("BCJSSE");
SSLEngine engine = context.createSSLEngine();
getParameters = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
@Override
public Method run() throws Exception {
return testBCSslEngine.getMethod("getParameters");
}
});
final Object bcSslParameters = getParameters.invoke(engine);
final Class<?> bCSslParametersClass = bcSslParameters.getClass();
setParameters = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
@Override
public Method run() throws Exception {
return testBCSslEngine.getMethod("setParameters", bCSslParametersClass);
}
});
setParameters.invoke(engine, bcSslParameters);
setApplicationProtocols = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
@Override
public Method run() throws Exception {
return bCSslParametersClass.getMethod("setApplicationProtocols", String[].class);
}
});
setApplicationProtocols.invoke(bcSslParameters, new Object[]{EmptyArrays.EMPTY_STRINGS});
getApplicationProtocol = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
@Override
public Method run() throws Exception {
return testBCSslEngine.getMethod("getApplicationProtocol");
}
});
getApplicationProtocol.invoke(engine);
getHandshakeApplicationProtocol = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
@Override
public Method run() throws Exception {
return testBCSslEngine.getMethod("getHandshakeApplicationProtocol");
}
});
getHandshakeApplicationProtocol.invoke(engine);
setHandshakeApplicationProtocolSelector =
AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
@Override
public Method run() throws Exception {
return testBCSslEngine.getMethod("setBCHandshakeApplicationProtocolSelector",
testBCApplicationProtocolSelector);
}
});
getHandshakeApplicationProtocolSelector =
AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
@Override
public Method run() throws Exception {
return testBCSslEngine.getMethod("getBCHandshakeApplicationProtocolSelector");
}
});
getHandshakeApplicationProtocolSelector.invoke(engine);
} catch (Throwable t) {
logger.error("Unable to initialize BouncyCastleAlpnSslUtils.", t);
setParameters = null;
getParameters = null;
setApplicationProtocols = null;
getApplicationProtocol = null;
getHandshakeApplicationProtocol = null;
setHandshakeApplicationProtocolSelector = null;
getHandshakeApplicationProtocolSelector = null;
bcApplicationProtocolSelectorSelect = null;
bcApplicationProtocolSelector = null;
}
SET_PARAMETERS = setParameters;
GET_PARAMETERS = getParameters;
SET_APPLICATION_PROTOCOLS = setApplicationProtocols;
GET_APPLICATION_PROTOCOL = getApplicationProtocol;
GET_HANDSHAKE_APPLICATION_PROTOCOL = getHandshakeApplicationProtocol;
SET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR = setHandshakeApplicationProtocolSelector;
GET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR = getHandshakeApplicationProtocolSelector;
BC_APPLICATION_PROTOCOL_SELECTOR_SELECT = bcApplicationProtocolSelectorSelect;
BC_APPLICATION_PROTOCOL_SELECTOR = bcApplicationProtocolSelector;
}
private BouncyCastleAlpnSslUtils() {
}
static String getApplicationProtocol(SSLEngine sslEngine) {
try {
return (String) GET_APPLICATION_PROTOCOL.invoke(sslEngine);
} catch (UnsupportedOperationException ex) {
throw ex;
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
static void setApplicationProtocols(SSLEngine engine, List<String> supportedProtocols) {
String[] protocolArray = supportedProtocols.toArray(EmptyArrays.EMPTY_STRINGS);
try {
Object bcSslParameters = GET_PARAMETERS.invoke(engine);
SET_APPLICATION_PROTOCOLS.invoke(bcSslParameters, new Object[]{protocolArray});
SET_PARAMETERS.invoke(engine, bcSslParameters);
} catch (UnsupportedOperationException ex) {
throw ex;
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
if (PlatformDependent.javaVersion() >= 9) {
JdkAlpnSslUtils.setApplicationProtocols(engine, supportedProtocols);
}
}
static String getHandshakeApplicationProtocol(SSLEngine sslEngine) {
try {
return (String) GET_HANDSHAKE_APPLICATION_PROTOCOL.invoke(sslEngine);
} catch (UnsupportedOperationException ex) {
throw ex;
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
static void setHandshakeApplicationProtocolSelector(
SSLEngine engine, final BiFunction<SSLEngine, List<String>, String> selector) {
try {
Object selectorProxyInstance = Proxy.newProxyInstance(
BouncyCastleAlpnSslUtils.class.getClassLoader(),
new Class[]{BC_APPLICATION_PROTOCOL_SELECTOR},