Search in sources :

Example 1 with AsymmetricSecurityHeader

use of org.eclipse.milo.opcua.stack.core.channel.headers.AsymmetricSecurityHeader 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 AsymmetricSecurityHeader

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

the class UascClientMessageHandler method onOpenSecureChannel.

private void onOpenSecureChannel(ChannelHandlerContext ctx, ByteBuf buffer) throws UaException {
    if (secureChannelTimeout != null) {
        if (secureChannelTimeout.cancel()) {
            logger.debug("OpenSecureChannel timeout canceled");
            secureChannelTimeout = null;
        } else {
            logger.warn("timed out waiting for secure channel");
            handshakeFuture.completeExceptionally(new UaException(StatusCodes.Bad_Timeout, "timed out waiting for secure channel"));
            ctx.close();
            return;
        }
    }
    // skip messageType, chunkType, messageSize, secureChannelId
    buffer.skipBytes(3 + 1 + 4 + 4);
    AsymmetricSecurityHeader securityHeader = AsymmetricSecurityHeader.decode(buffer, config.getEncodingLimits());
    if (headerRef.compareAndSet(null, securityHeader)) {
        // first time we've received the header; validate and verify the server certificate
        CertificateValidator certificateValidator = config.getCertificateValidator();
        SecurityPolicy securityPolicy = SecurityPolicy.fromUri(securityHeader.getSecurityPolicyUri());
        if (securityPolicy != SecurityPolicy.None) {
            ByteString serverCertificateBytes = securityHeader.getSenderCertificate();
            List<X509Certificate> serverCertificateChain = CertificateUtil.decodeCertificates(serverCertificateBytes.bytesOrEmpty());
            certificateValidator.validateCertificateChain(serverCertificateChain);
        }
    } else {
        if (!securityHeader.equals(headerRef.get())) {
            throw new UaException(StatusCodes.Bad_SecurityChecksFailed, "subsequent AsymmetricSecurityHeader did not match");
        }
    }
    if (accumulateChunk(buffer)) {
        final List<ByteBuf> buffersToDecode = chunkBuffers;
        chunkBuffers = new ArrayList<>(maxChunkCount);
        serializationQueue.decode((binaryDecoder, chunkDecoder) -> {
            ByteBuf message;
            try {
                ChunkDecoder.DecodedMessage decodedMessage = chunkDecoder.decodeAsymmetric(secureChannel, buffersToDecode);
                message = decodedMessage.getMessage();
            } 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);
                handshakeFuture.completeExceptionally(e);
                ctx.close();
                return;
            }
            try {
                UaResponseMessage response = (UaResponseMessage) binaryDecoder.setBuffer(message).readMessage(null);
                StatusCode serviceResult = response.getResponseHeader().getServiceResult();
                if (serviceResult.isGood()) {
                    OpenSecureChannelResponse oscr = (OpenSecureChannelResponse) response;
                    secureChannel.setChannelId(oscr.getSecurityToken().getChannelId().longValue());
                    logger.debug("Received OpenSecureChannelResponse.");
                    NonceUtil.validateNonce(oscr.getServerNonce(), secureChannel.getSecurityPolicy());
                    installSecurityToken(ctx, oscr);
                    handshakeFuture.complete(secureChannel);
                } else {
                    ServiceFault serviceFault = (response instanceof ServiceFault) ? (ServiceFault) response : new ServiceFault(response.getResponseHeader());
                    handshakeFuture.completeExceptionally(new UaServiceFaultException(serviceFault));
                    ctx.close();
                }
            } catch (Throwable t) {
                logger.error("Error decoding OpenSecureChannelResponse", t);
                handshakeFuture.completeExceptionally(t);
                ctx.close();
            } finally {
                message.release();
            }
        });
    }
}
Also used : UaResponseMessage(org.eclipse.milo.opcua.stack.core.serialization.UaResponseMessage) OpenSecureChannelResponse(org.eclipse.milo.opcua.stack.core.types.structured.OpenSecureChannelResponse) UaException(org.eclipse.milo.opcua.stack.core.UaException) ByteString(org.eclipse.milo.opcua.stack.core.types.builtin.ByteString) CertificateValidator(org.eclipse.milo.opcua.stack.core.security.CertificateValidator) MessageAbortException(org.eclipse.milo.opcua.stack.core.channel.MessageAbortException) CompositeByteBuf(io.netty.buffer.CompositeByteBuf) ByteBuf(io.netty.buffer.ByteBuf) StatusCode(org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode) X509Certificate(java.security.cert.X509Certificate) UaServiceFaultException(org.eclipse.milo.opcua.stack.core.UaServiceFaultException) ChunkDecoder(org.eclipse.milo.opcua.stack.core.channel.ChunkDecoder) ServiceFault(org.eclipse.milo.opcua.stack.core.types.structured.ServiceFault) 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)

Aggregations

ByteBuf (io.netty.buffer.ByteBuf)2 CompositeByteBuf (io.netty.buffer.CompositeByteBuf)2 X509Certificate (java.security.cert.X509Certificate)2 UaException (org.eclipse.milo.opcua.stack.core.UaException)2 ChunkDecoder (org.eclipse.milo.opcua.stack.core.channel.ChunkDecoder)2 MessageAbortException (org.eclipse.milo.opcua.stack.core.channel.MessageAbortException)2 MessageDecodeException (org.eclipse.milo.opcua.stack.core.channel.MessageDecodeException)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 ByteString (org.eclipse.milo.opcua.stack.core.types.builtin.ByteString)2 KeyPair (java.security.KeyPair)1 UaServiceFaultException (org.eclipse.milo.opcua.stack.core.UaServiceFaultException)1 ServerSecureChannel (org.eclipse.milo.opcua.stack.core.channel.ServerSecureChannel)1 CertificateManager (org.eclipse.milo.opcua.stack.core.security.CertificateManager)1 UaResponseMessage (org.eclipse.milo.opcua.stack.core.serialization.UaResponseMessage)1 StatusCode (org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode)1 Unsigned.uint (org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint)1 OpenSecureChannelRequest (org.eclipse.milo.opcua.stack.core.types.structured.OpenSecureChannelRequest)1 OpenSecureChannelResponse (org.eclipse.milo.opcua.stack.core.types.structured.OpenSecureChannelResponse)1