Search in sources :

Example 1 with ChunkDecoder

use of org.eclipse.milo.opcua.stack.core.channel.ChunkDecoder in project milo by eclipse.

the class UascServerAsymmetricHandler method onOpenSecureChannel.

private void onOpenSecureChannel(ChannelHandlerContext ctx, ByteBuf buffer) throws UaException {
    // Skip messageType
    buffer.skipBytes(3);
    char chunkType = (char) buffer.readByte();
    if (chunkType == 'A') {
        chunkBuffers.forEach(ByteBuf::release);
        chunkBuffers.clear();
        headerRef.set(null);
    } else {
        // Skip messageSize
        buffer.skipBytes(4);
        final long secureChannelId = buffer.readUnsignedIntLE();
        final AsymmetricSecurityHeader header = AsymmetricSecurityHeader.decode(buffer, stackServer.getConfig().getEncodingLimits());
        if (!headerRef.compareAndSet(null, header)) {
            if (!header.equals(headerRef.get())) {
                throw new UaException(StatusCodes.Bad_SecurityChecksFailed, "subsequent AsymmetricSecurityHeader did not match");
            }
        }
        if (secureChannelId != 0) {
            if (secureChannel == null) {
                throw new UaException(StatusCodes.Bad_TcpSecureChannelUnknown, "unknown secure channel id: " + secureChannelId);
            }
            if (secureChannelId != secureChannel.getChannelId()) {
                throw new UaException(StatusCodes.Bad_TcpSecureChannelUnknown, "unknown secure channel id: " + secureChannelId);
            }
        }
        if (secureChannel == null) {
            secureChannel = new ServerSecureChannel();
            secureChannel.setChannelId(stackServer.getNextChannelId());
            String securityPolicyUri = header.getSecurityPolicyUri();
            SecurityPolicy securityPolicy = SecurityPolicy.fromUri(securityPolicyUri);
            secureChannel.setSecurityPolicy(securityPolicy);
            if (securityPolicy != SecurityPolicy.None) {
                secureChannel.setRemoteCertificate(header.getSenderCertificate().bytesOrEmpty());
                CertificateValidator certificateValidator = stackServer.getConfig().getCertificateValidator();
                certificateValidator.validateCertificateChain(secureChannel.getRemoteCertificateChain());
                CertificateManager certificateManager = stackServer.getConfig().getCertificateManager();
                Optional<X509Certificate[]> localCertificateChain = certificateManager.getCertificateChain(header.getReceiverThumbprint());
                Optional<KeyPair> keyPair = certificateManager.getKeyPair(header.getReceiverThumbprint());
                if (localCertificateChain.isPresent() && keyPair.isPresent()) {
                    X509Certificate[] chain = localCertificateChain.get();
                    secureChannel.setLocalCertificate(chain[0]);
                    secureChannel.setLocalCertificateChain(chain);
                    secureChannel.setKeyPair(keyPair.get());
                } else {
                    throw new UaException(StatusCodes.Bad_SecurityChecksFailed, "no certificate for provided thumbprint");
                }
            }
        }
        int chunkSize = buffer.readerIndex(0).readableBytes();
        if (chunkSize > maxChunkSize) {
            throw new UaException(StatusCodes.Bad_TcpMessageTooLarge, String.format("max chunk size exceeded (%s)", maxChunkSize));
        }
        chunkBuffers.add(buffer.retain());
        if (maxChunkCount > 0 && chunkBuffers.size() > maxChunkCount) {
            throw new UaException(StatusCodes.Bad_TcpMessageTooLarge, String.format("max chunk count exceeded (%s)", maxChunkCount));
        }
        if (chunkType == 'F') {
            final List<ByteBuf> buffersToDecode = chunkBuffers;
            chunkBuffers = new ArrayList<>();
            headerRef.set(null);
            serializationQueue.decode((binaryDecoder, chunkDecoder) -> {
                ByteBuf message;
                long requestId;
                try {
                    ChunkDecoder.DecodedMessage decodedMessage = chunkDecoder.decodeAsymmetric(secureChannel, buffersToDecode);
                    message = decodedMessage.getMessage();
                    requestId = decodedMessage.getRequestId();
                } catch (MessageAbortException e) {
                    logger.warn("Received message abort chunk; error={}, reason={}", e.getStatusCode(), e.getMessage());
                    return;
                } catch (MessageDecodeException e) {
                    logger.error("Error decoding asymmetric message", e);
                    ctx.close();
                    return;
                }
                try {
                    OpenSecureChannelRequest request = (OpenSecureChannelRequest) binaryDecoder.setBuffer(message).readMessage(null);
                    logger.debug("Received OpenSecureChannelRequest ({}, id={}).", request.getRequestType(), secureChannelId);
                    sendOpenSecureChannelResponse(ctx, requestId, request);
                } catch (Throwable t) {
                    logger.error("Error decoding OpenSecureChannelRequest", t);
                    ctx.close();
                } finally {
                    message.release();
                    buffersToDecode.clear();
                }
            });
        }
    }
}
Also used : ServerSecureChannel(org.eclipse.milo.opcua.stack.core.channel.ServerSecureChannel) KeyPair(java.security.KeyPair) UaException(org.eclipse.milo.opcua.stack.core.UaException) CertificateValidator(org.eclipse.milo.opcua.stack.core.security.CertificateValidator) CertificateManager(org.eclipse.milo.opcua.stack.core.security.CertificateManager) MessageAbortException(org.eclipse.milo.opcua.stack.core.channel.MessageAbortException) ByteString(org.eclipse.milo.opcua.stack.core.types.builtin.ByteString) CompositeByteBuf(io.netty.buffer.CompositeByteBuf) ByteBuf(io.netty.buffer.ByteBuf) X509Certificate(java.security.cert.X509Certificate) Unsigned.uint(org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint) OpenSecureChannelRequest(org.eclipse.milo.opcua.stack.core.types.structured.OpenSecureChannelRequest) ChunkDecoder(org.eclipse.milo.opcua.stack.core.channel.ChunkDecoder) SecurityPolicy(org.eclipse.milo.opcua.stack.core.security.SecurityPolicy) MessageDecodeException(org.eclipse.milo.opcua.stack.core.channel.MessageDecodeException) AsymmetricSecurityHeader(org.eclipse.milo.opcua.stack.core.channel.headers.AsymmetricSecurityHeader)

Example 2 with ChunkDecoder

use of org.eclipse.milo.opcua.stack.core.channel.ChunkDecoder in project milo by eclipse.

the class UascServerSymmetricHandler method onSecureMessage.

private void onSecureMessage(ChannelHandlerContext ctx, ByteBuf buffer) throws UaException {
    // Skip messageType
    buffer.skipBytes(3);
    char chunkType = (char) buffer.readByte();
    if (chunkType == 'A') {
        chunkBuffers.forEach(ByteBuf::release);
        chunkBuffers.clear();
    } else {
        // Skip messageSize
        buffer.skipBytes(4);
        long secureChannelId = buffer.readUnsignedIntLE();
        if (secureChannelId != secureChannel.getChannelId()) {
            throw new UaException(StatusCodes.Bad_SecureChannelIdInvalid, "invalid secure channel id: " + secureChannelId);
        }
        int chunkSize = buffer.readerIndex(0).readableBytes();
        if (chunkSize > maxChunkSize) {
            throw new UaException(StatusCodes.Bad_TcpMessageTooLarge, String.format("max chunk size exceeded (%s)", maxChunkSize));
        }
        chunkBuffers.add(buffer.retain());
        if (maxChunkCount > 0 && chunkBuffers.size() > maxChunkCount) {
            throw new UaException(StatusCodes.Bad_TcpMessageTooLarge, String.format("max chunk count exceeded (%s)", maxChunkCount));
        }
        if (chunkType == 'F') {
            final List<ByteBuf> buffersToDecode = chunkBuffers;
            chunkBuffers = new ArrayList<>();
            serializationQueue.decode((binaryDecoder, chunkDecoder) -> {
                ByteBuf message;
                long requestId;
                try {
                    ChunkDecoder.DecodedMessage decodedMessage = chunkDecoder.decodeSymmetric(secureChannel, buffersToDecode);
                    message = decodedMessage.getMessage();
                    requestId = decodedMessage.getRequestId();
                } catch (MessageAbortException e) {
                    logger.warn("Received message abort chunk; error={}, reason={}", e.getStatusCode(), e.getMessage());
                    return;
                } catch (MessageDecodeException e) {
                    logger.error("Error decoding symmetric message", e);
                    ctx.close();
                    return;
                }
                try {
                    UaRequestMessage request = (UaRequestMessage) binaryDecoder.setBuffer(message).readMessage(null);
                    String endpointUrl = ctx.channel().attr(UascServerHelloHandler.ENDPOINT_URL_KEY).get();
                    EndpointDescription endpoint = ctx.channel().attr(UascServerAsymmetricHandler.ENDPOINT_KEY).get();
                    String path = EndpointUtil.getPath(endpointUrl);
                    InetSocketAddress remoteSocketAddress = (InetSocketAddress) ctx.channel().remoteAddress();
                    ServiceRequest serviceRequest = new ServiceRequest(stackServer, request, endpoint, secureChannel.getChannelId(), remoteSocketAddress.getAddress(), secureChannel.getRemoteCertificateBytes());
                    serviceRequest.getFuture().whenComplete((response, fault) -> {
                        if (response != null) {
                            sendServiceResponse(ctx, requestId, request, response);
                        } else {
                            UInteger requestHandle = request.getRequestHeader().getRequestHandle();
                            sendServiceFault(ctx, requestId, requestHandle, fault);
                        }
                    });
                    stackServer.onServiceRequest(path, serviceRequest);
                } catch (UaSerializationException e) {
                    logger.error("Error decoding UaRequestMessage", e);
                    sendServiceFault(ctx, requestId, uint(0), e);
                } catch (Throwable t) {
                    logger.error("Unexpected error servicing UaRequestMessage", t);
                    long statusCode = UaException.extractStatusCode(t).map(StatusCode::getValue).orElse(StatusCodes.Bad_UnexpectedError);
                    sendServiceFault(ctx, requestId, uint(0), new UaException(statusCode, t));
                } finally {
                    message.release();
                    buffersToDecode.clear();
                }
            });
        }
    }
}
Also used : UaSerializationException(org.eclipse.milo.opcua.stack.core.UaSerializationException) UaRequestMessage(org.eclipse.milo.opcua.stack.core.serialization.UaRequestMessage) UaException(org.eclipse.milo.opcua.stack.core.UaException) InetSocketAddress(java.net.InetSocketAddress) MessageAbortException(org.eclipse.milo.opcua.stack.core.channel.MessageAbortException) EndpointDescription(org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription) ByteBuf(io.netty.buffer.ByteBuf) CompositeByteBuf(io.netty.buffer.CompositeByteBuf) StatusCode(org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode) Unsigned.uint(org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint) ServiceRequest(org.eclipse.milo.opcua.stack.server.services.ServiceRequest) ChunkDecoder(org.eclipse.milo.opcua.stack.core.channel.ChunkDecoder) UInteger(org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger) MessageDecodeException(org.eclipse.milo.opcua.stack.core.channel.MessageDecodeException)

Example 3 with ChunkDecoder

use of org.eclipse.milo.opcua.stack.core.channel.ChunkDecoder in project milo by eclipse.

the class ChunkSerializationTest method testSymmetric4096.

@Test
public void testSymmetric4096() throws Exception {
    ChannelParameters parameters = defaultParameters;
    ChunkEncoder encoder = new ChunkEncoder(parameters);
    ChunkDecoder decoder = new ChunkDecoder(parameters, EncodingLimits.DEFAULT);
    SecureChannel[] channels = generateChannels4096();
    ClientSecureChannel clientChannel = (ClientSecureChannel) channels[0];
    ServerSecureChannel serverChannel = (ServerSecureChannel) channels[1];
    clientChannel.attr(ClientSecureChannel.KEY_REQUEST_ID_SEQUENCE).setIfAbsent(new LongSequence(1L, UInteger.MAX_VALUE));
    LongSequence requestId = clientChannel.attr(ClientSecureChannel.KEY_REQUEST_ID_SEQUENCE).get();
    for (int messageSize = 0; messageSize < 1024; messageSize++) {
        byte[] messageBytes = new byte[messageSize];
        for (int i = 0; i < messageBytes.length; i++) {
            messageBytes[i] = (byte) i;
        }
        ByteBuf messageBuffer = BufferUtil.pooledBuffer().writeBytes(messageBytes);
        List<ByteBuf> chunkBuffers = new ArrayList<>();
        try {
            ChunkEncoder.EncodedMessage message = encoder.encodeSymmetric(clientChannel, requestId.getAndIncrement(), messageBuffer, MessageType.OpenSecureChannel);
            chunkBuffers.addAll(message.getMessageChunks());
        } catch (MessageEncodeException e) {
            fail("encoding error", e);
        }
        try {
            ChunkDecoder.DecodedMessage decodedMessage = decoder.decodeSymmetric(serverChannel, chunkBuffers);
            ByteBuf message = decodedMessage.getMessage();
            messageBuffer.readerIndex(0);
            assertEquals(message, messageBuffer);
            ReferenceCountUtil.release(message);
            ReferenceCountUtil.release(messageBuffer);
        } catch (Throwable t) {
            fail("decoding error", t);
        }
    }
}
Also used : ServerSecureChannel(org.eclipse.milo.opcua.stack.core.channel.ServerSecureChannel) ChannelParameters(org.eclipse.milo.opcua.stack.core.channel.ChannelParameters) ChunkEncoder(org.eclipse.milo.opcua.stack.core.channel.ChunkEncoder) ClientSecureChannel(org.eclipse.milo.opcua.stack.client.transport.uasc.ClientSecureChannel) ArrayList(java.util.ArrayList) ServerSecureChannel(org.eclipse.milo.opcua.stack.core.channel.ServerSecureChannel) SecureChannel(org.eclipse.milo.opcua.stack.core.channel.SecureChannel) ClientSecureChannel(org.eclipse.milo.opcua.stack.client.transport.uasc.ClientSecureChannel) ByteBuf(io.netty.buffer.ByteBuf) ChunkDecoder(org.eclipse.milo.opcua.stack.core.channel.ChunkDecoder) LongSequence(org.eclipse.milo.opcua.stack.core.util.LongSequence) MessageEncodeException(org.eclipse.milo.opcua.stack.core.channel.MessageEncodeException) Test(org.testng.annotations.Test)

Example 4 with ChunkDecoder

use of org.eclipse.milo.opcua.stack.core.channel.ChunkDecoder in project milo by eclipse.

the class ChunkSerializationTest method testAsymmetric4096.

@Test
public void testAsymmetric4096() throws Exception {
    ChannelParameters parameters = defaultParameters;
    ChunkEncoder encoder = new ChunkEncoder(parameters);
    ChunkDecoder decoder = new ChunkDecoder(parameters, EncodingLimits.DEFAULT);
    SecureChannel[] channels = generateChannels4096();
    ClientSecureChannel clientChannel = (ClientSecureChannel) channels[0];
    ServerSecureChannel serverChannel = (ServerSecureChannel) channels[1];
    clientChannel.attr(ClientSecureChannel.KEY_REQUEST_ID_SEQUENCE).setIfAbsent(new LongSequence(1L, UInteger.MAX_VALUE));
    LongSequence requestId = clientChannel.attr(ClientSecureChannel.KEY_REQUEST_ID_SEQUENCE).get();
    for (int messageSize = 0; messageSize < 512; messageSize++) {
        byte[] messageBytes = new byte[messageSize];
        for (int i = 0; i < messageBytes.length; i++) {
            messageBytes[i] = (byte) i;
        }
        ByteBuf messageBuffer = BufferUtil.pooledBuffer().writeBytes(messageBytes);
        List<ByteBuf> chunkBuffers = new ArrayList<>();
        try {
            ChunkEncoder.EncodedMessage message = encoder.encodeAsymmetric(clientChannel, requestId.getAndIncrement(), messageBuffer, MessageType.OpenSecureChannel);
            chunkBuffers.addAll(message.getMessageChunks());
        } catch (MessageEncodeException e) {
            fail("encoding error", e);
        }
        try {
            ChunkDecoder.DecodedMessage decodedMessage = decoder.decodeAsymmetric(serverChannel, chunkBuffers);
            ByteBuf message = decodedMessage.getMessage();
            messageBuffer.readerIndex(0);
            assertEquals(message, messageBuffer);
            ReferenceCountUtil.release(message);
            ReferenceCountUtil.release(messageBuffer);
        } catch (Throwable t) {
            fail("decoding error", t);
        }
    }
}
Also used : ServerSecureChannel(org.eclipse.milo.opcua.stack.core.channel.ServerSecureChannel) ChannelParameters(org.eclipse.milo.opcua.stack.core.channel.ChannelParameters) ChunkEncoder(org.eclipse.milo.opcua.stack.core.channel.ChunkEncoder) ClientSecureChannel(org.eclipse.milo.opcua.stack.client.transport.uasc.ClientSecureChannel) ArrayList(java.util.ArrayList) ServerSecureChannel(org.eclipse.milo.opcua.stack.core.channel.ServerSecureChannel) SecureChannel(org.eclipse.milo.opcua.stack.core.channel.SecureChannel) ClientSecureChannel(org.eclipse.milo.opcua.stack.client.transport.uasc.ClientSecureChannel) ByteBuf(io.netty.buffer.ByteBuf) ChunkDecoder(org.eclipse.milo.opcua.stack.core.channel.ChunkDecoder) LongSequence(org.eclipse.milo.opcua.stack.core.util.LongSequence) MessageEncodeException(org.eclipse.milo.opcua.stack.core.channel.MessageEncodeException) Test(org.testng.annotations.Test)

Example 5 with ChunkDecoder

use of org.eclipse.milo.opcua.stack.core.channel.ChunkDecoder in project milo by eclipse.

the class ChunkSerializationTest method testSymmetricMessage.

@Test(dataProvider = "getSymmetricSecurityParameters")
public void testSymmetricMessage(SecurityPolicy securityPolicy, MessageSecurityMode messageSecurity) throws Exception {
    logger.info("Symmetric chunk serialization, " + "securityPolicy={}, messageSecurityMode={}", securityPolicy, messageSecurity);
    ChannelParameters[] channelParameters = { smallParameters, defaultParameters, unlimitedChunkCountParameters, unlimitedMessageSizeParameters };
    for (ChannelParameters parameters : channelParameters) {
        int[] messageSizes = new int[] { 128, parameters.getRemoteMaxMessageSize() };
        for (int messageSize : messageSizes) {
            ChunkEncoder encoder = new ChunkEncoder(parameters);
            ChunkDecoder decoder = new ChunkDecoder(parameters, EncodingLimits.DEFAULT);
            SecureChannel[] channels = generateChannels(securityPolicy, messageSecurity);
            ClientSecureChannel clientChannel = (ClientSecureChannel) channels[0];
            ServerSecureChannel serverChannel = (ServerSecureChannel) channels[1];
            clientChannel.attr(ClientSecureChannel.KEY_REQUEST_ID_SEQUENCE).setIfAbsent(new LongSequence(1L, UInteger.MAX_VALUE));
            LongSequence requestId = clientChannel.attr(ClientSecureChannel.KEY_REQUEST_ID_SEQUENCE).get();
            byte[] messageBytes = new byte[messageSize];
            for (int i = 0; i < messageBytes.length; i++) {
                messageBytes[i] = (byte) i;
            }
            ByteBuf messageBuffer = BufferUtil.pooledBuffer().writeBytes(messageBytes);
            List<ByteBuf> chunkBuffers = new ArrayList<>();
            try {
                ChunkEncoder.EncodedMessage message = encoder.encodeSymmetric(clientChannel, requestId.getAndIncrement(), messageBuffer, MessageType.SecureMessage);
                chunkBuffers.addAll(message.getMessageChunks());
            } catch (MessageEncodeException e) {
                fail("encoding error", e);
            }
            try {
                ChunkDecoder.DecodedMessage decodedMessage = decoder.decodeSymmetric(serverChannel, chunkBuffers);
                ByteBuf message = decodedMessage.getMessage();
                messageBuffer.readerIndex(0);
                assertEquals(message, messageBuffer);
                ReferenceCountUtil.release(messageBuffer);
                ReferenceCountUtil.release(message);
            } catch (Throwable t) {
                fail("decoding error", t);
            }
        }
    }
}
Also used : ServerSecureChannel(org.eclipse.milo.opcua.stack.core.channel.ServerSecureChannel) ChannelParameters(org.eclipse.milo.opcua.stack.core.channel.ChannelParameters) ChunkEncoder(org.eclipse.milo.opcua.stack.core.channel.ChunkEncoder) ClientSecureChannel(org.eclipse.milo.opcua.stack.client.transport.uasc.ClientSecureChannel) ArrayList(java.util.ArrayList) ServerSecureChannel(org.eclipse.milo.opcua.stack.core.channel.ServerSecureChannel) SecureChannel(org.eclipse.milo.opcua.stack.core.channel.SecureChannel) ClientSecureChannel(org.eclipse.milo.opcua.stack.client.transport.uasc.ClientSecureChannel) ByteBuf(io.netty.buffer.ByteBuf) ChunkDecoder(org.eclipse.milo.opcua.stack.core.channel.ChunkDecoder) LongSequence(org.eclipse.milo.opcua.stack.core.util.LongSequence) MessageEncodeException(org.eclipse.milo.opcua.stack.core.channel.MessageEncodeException) Test(org.testng.annotations.Test)

Aggregations

ByteBuf (io.netty.buffer.ByteBuf)8 ChunkDecoder (org.eclipse.milo.opcua.stack.core.channel.ChunkDecoder)8 ServerSecureChannel (org.eclipse.milo.opcua.stack.core.channel.ServerSecureChannel)5 CompositeByteBuf (io.netty.buffer.CompositeByteBuf)4 ArrayList (java.util.ArrayList)4 ClientSecureChannel (org.eclipse.milo.opcua.stack.client.transport.uasc.ClientSecureChannel)4 UaException (org.eclipse.milo.opcua.stack.core.UaException)4 ChannelParameters (org.eclipse.milo.opcua.stack.core.channel.ChannelParameters)4 ChunkEncoder (org.eclipse.milo.opcua.stack.core.channel.ChunkEncoder)4 MessageAbortException (org.eclipse.milo.opcua.stack.core.channel.MessageAbortException)4 MessageDecodeException (org.eclipse.milo.opcua.stack.core.channel.MessageDecodeException)4 MessageEncodeException (org.eclipse.milo.opcua.stack.core.channel.MessageEncodeException)4 SecureChannel (org.eclipse.milo.opcua.stack.core.channel.SecureChannel)4 LongSequence (org.eclipse.milo.opcua.stack.core.util.LongSequence)4 Test (org.testng.annotations.Test)4 X509Certificate (java.security.cert.X509Certificate)2 AsymmetricSecurityHeader (org.eclipse.milo.opcua.stack.core.channel.headers.AsymmetricSecurityHeader)2 CertificateValidator (org.eclipse.milo.opcua.stack.core.security.CertificateValidator)2 SecurityPolicy (org.eclipse.milo.opcua.stack.core.security.SecurityPolicy)2 UaResponseMessage (org.eclipse.milo.opcua.stack.core.serialization.UaResponseMessage)2