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();
}
});
}
}
}
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();
}
});
}
}
Aggregations