Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add coaps+tcp support based on java-coap to client and server. #1607

Merged
merged 4 commits into from
Apr 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
import org.eclipse.leshan.core.request.ContentFormat;
import org.eclipse.leshan.core.response.BootstrapWriteResponse;
import org.eclipse.leshan.transport.javacoap.client.coaptcp.endpoint.JavaCoapTcpClientEndpointsProvider;
import org.eclipse.leshan.transport.javacoap.client.coaptcp.endpoint.JavaCoapsTcpClientEndpointsProvider;
import org.eclipse.leshan.transport.javacoap.client.endpoint.JavaCoapClientEndpointsProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -319,6 +320,7 @@ protected DtlsConnectorConfig.Builder createRootDtlsConnectorConfigBuilder(
endpointsProvider.add(new JavaCoapClientEndpointsProvider());
}
endpointsProvider.add(new JavaCoapTcpClientEndpointsProvider());
endpointsProvider.add(new JavaCoapsTcpClientEndpointsProvider());

// Create client
LeshanClientBuilder builder = new LeshanClientBuilder(cli.main.endpoint);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@
import java.io.File;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.eclipse.californium.core.coap.CoAP;
import org.eclipse.californium.scandium.dtls.cipher.CipherSuite;
Expand All @@ -31,6 +34,7 @@
import org.eclipse.leshan.core.demo.cli.converters.InetAddressConverter;
import org.eclipse.leshan.core.demo.cli.converters.ResourcePathConverter;
import org.eclipse.leshan.core.demo.cli.converters.StrictlyPositiveIntegerConverter;
import org.eclipse.leshan.core.endpoint.Protocol;
import org.eclipse.leshan.core.node.LwM2mPath;
import org.eclipse.leshan.core.util.StringUtils;

Expand Down Expand Up @@ -316,24 +320,33 @@ public void run() {
// extract scheme
int indexOf = main.url.indexOf("://");
String scheme = main.url.substring(0, indexOf);
// we support only coap and coaps
if (!"coap".equals(scheme) && !"coaps".equals(scheme) && !"coap+tcp".equals(scheme)) {
throw new MultiParameterException(spec.commandLine(), String.format(
"Invalid URL %s : unknown scheme '%s', we support only 'coap' or 'coaps' or 'coap+tcp' for now",
main.url, scheme), "-u");
// check URI scheme is supported
List<String> supportedUnsecuredProtocol = Arrays.asList(Protocol.COAP, Protocol.COAP_TCP) //
.stream().map(Protocol::getUriScheme).collect(Collectors.toList());
List<String> supportedTlsBasedProtocol = Arrays.asList(Protocol.COAPS, Protocol.COAPS_TCP) //
.stream().map(Protocol::getUriScheme).collect(Collectors.toList());
List<String> allSupportedProtocol = Stream
.concat(supportedUnsecuredProtocol.stream(), supportedTlsBasedProtocol.stream())
.collect(Collectors.toList());

if (!allSupportedProtocol.contains(scheme)) {
throw new MultiParameterException(spec.commandLine(),
String.format("Invalid URL %s : unknown scheme '%s', we support only %s for now", main.url, scheme,
String.join(" or ", allSupportedProtocol)),
"-u");
}
// check scheme matches configuration
if (identity.hasIdentity()) {
if (!scheme.equals("coaps")) {
if (!supportedTlsBasedProtocol.contains(scheme)) {
throw new MultiParameterException(spec.commandLine(), String.format(
"Invalid URL %s : '%s' scheme must be used without PSK, RPK or x509 option. Do you mean 'coaps' ? ",
main.url, scheme), "-u");
"Invalid URL %s : '%s' scheme must be used without PSK, RPK or x509 option. Do you mean %s ? ",
main.url, scheme, String.join(" or ", supportedTlsBasedProtocol)), "-u");
}
} else {
if (!scheme.equals("coap") && !scheme.equals("coap+tcp")) {
if (!supportedUnsecuredProtocol.contains(scheme)) {
throw new MultiParameterException(spec.commandLine(), String.format(
"Invalid URL %s : '%s' scheme must be used with PSK, RPK or x509 option. Do you mean 'coap' ? ",
main.url, scheme), "-u");
"Invalid URL %s : '%s' scheme must be used with PSK, RPK or x509 option. Do you mean %s ? ",
main.url, scheme, String.join(" or ", supportedUnsecuredProtocol)), "-u");
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*******************************************************************************
* Copyright (c) 2024 Sierra Wireless and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v20.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.html.
*
* Contributors:
* Sierra Wireless - initial API and implementation
*******************************************************************************/
package org.eclipse.leshan.core.security.jsse;

import java.net.InetSocketAddress;
import java.net.Socket;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Arrays;

import javax.net.ssl.SSLEngine;
import javax.net.ssl.X509ExtendedTrustManager;

import org.eclipse.leshan.core.security.certificate.util.CertPathUtil;
import org.eclipse.leshan.core.security.certificate.verifier.X509CertificateVerifier;
import org.eclipse.leshan.core.security.certificate.verifier.X509CertificateVerifier.Role;

public class LwM2mX509TrustManager extends X509ExtendedTrustManager {

private final X509CertificateVerifier certificateVerifier;

public LwM2mX509TrustManager(X509CertificateVerifier certificateVerifier) {
this.certificateVerifier = certificateVerifier;
}

@Override
public X509Certificate[] getAcceptedIssuers() {
// TODO not clear what this is about...
return new X509Certificate[0];
}

@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
throw new UnsupportedOperationException();
}

@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
throw new UnsupportedOperationException();
}

@Override
public void checkClientTrusted(X509Certificate[] chain, String authType, Socket socket)
throws CertificateException {
certificateVerifier.verifyCertificate(CertPathUtil.generateCertPath(Arrays.asList(chain)),
getPeerAddress(socket), Role.CLIENT);
}

@Override
public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket)
throws CertificateException {
certificateVerifier.verifyCertificate(CertPathUtil.generateCertPath(Arrays.asList(chain)),
getPeerAddress(socket), Role.SERVER);
}

protected InetSocketAddress getPeerAddress(Socket socket) {
return (InetSocketAddress) socket.getRemoteSocketAddress();
}

@Override
public void checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine engine)
throws CertificateException {
certificateVerifier.verifyCertificate(CertPathUtil.generateCertPath(Arrays.asList(chain)),
getPeerAddress(engine), Role.CLIENT);
}

@Override
public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine engine)
throws CertificateException {
certificateVerifier.verifyCertificate(CertPathUtil.generateCertPath(Arrays.asList(chain)),
getPeerAddress(engine), Role.SERVER);
}

protected InetSocketAddress getPeerAddress(SSLEngine engine) {
if (engine.getPeerHost() == null)
return null;

return new InetSocketAddress(engine.getPeerHost(), engine.getPeerPort());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ public class X509Test {
static Stream<org.junit.jupiter.params.provider.Arguments> transports() {
return Stream.of(//
// ProtocolUsed - Client Endpoint Provider - Server Endpoint Provider
arguments(Protocol.COAPS, "Californium", "Californium"));
arguments(Protocol.COAPS, "Californium", "Californium"),
arguments(Protocol.COAPS_TCP, "java-coap", "java-coap"));
}

/*---------------------------------/
Expand Down Expand Up @@ -145,7 +146,7 @@ public void registered_device_with_x509cert_to_server_with_x509cert_then_remove_
server.getSecurityStore().remove(client.getEndpointName(), true);

// try to update
Thread.sleep(100);
Thread.sleep(200);
if (givenProtocol.equals(Protocol.COAPS)) {
// For DTLS, Client doesn't know that connection is removed at server side.
// So request will first timeout.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
import org.eclipse.leshan.server.bootstrap.endpoint.LwM2mBootstrapServerEndpoint;
import org.eclipse.leshan.server.endpoint.LwM2mServerEndpoint;
import org.eclipse.leshan.transport.javacoap.client.coaptcp.endpoint.JavaCoapTcpClientEndpointsProvider;
import org.eclipse.leshan.transport.javacoap.client.coaptcp.endpoint.JavaCoapsTcpClientEndpointsProvider;
import org.eclipse.leshan.transport.javacoap.client.endpoint.JavaCoapClientEndpointsProvider;

public class LeshanTestClientBuilder extends LeshanClientBuilder {
Expand Down Expand Up @@ -301,6 +302,8 @@ protected LwM2mClientEndpointsProvider getJavaCoapProtocolProvider(Protocol prot
return new JavaCoapClientEndpointsProvider();
} else if (protocolToUse.equals(Protocol.COAP_TCP)) {
return new JavaCoapTcpClientEndpointsProvider();
} else if (protocolToUse.equals(Protocol.COAPS_TCP)) {
return new JavaCoapsTcpClientEndpointsProvider();
}
throw new IllegalStateException(String.format("No Californium Protocol Provider for protocol %s", protocol));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
import org.eclipse.leshan.server.security.SecurityStore;
import org.eclipse.leshan.server.security.ServerSecurityInfo;
import org.eclipse.leshan.transport.javacoap.server.coaptcp.endpoint.JavaCoapTcpServerEndpointsProvider;
import org.eclipse.leshan.transport.javacoap.server.coaptcp.endpoint.JavaCoapsTcpServerEndpointsProvider;
import org.eclipse.leshan.transport.javacoap.server.endpoint.JavaCoapServerEndpointsProvider;

public class LeshanTestServerBuilder extends LeshanServerBuilder {
Expand Down Expand Up @@ -251,6 +252,8 @@ protected LwM2mServerEndpointsProvider getJavaCoapProtocolProvider(Protocol prot
return new JavaCoapServerEndpointsProvider(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
} else if (protocolToUse.equals(Protocol.COAP_TCP)) {
return new JavaCoapTcpServerEndpointsProvider(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
} else if (protocolToUse.equals(Protocol.COAPS_TCP)) {
return new JavaCoapsTcpServerEndpointsProvider(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
}
throw new IllegalStateException(String.format("No Californium Protocol Provider for protocol %s", protocol));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
import org.eclipse.leshan.server.security.EditableSecurityStore;
import org.eclipse.leshan.server.security.FileSecurityStore;
import org.eclipse.leshan.transport.javacoap.server.coaptcp.endpoint.JavaCoapTcpServerEndpointsProvider;
import org.eclipse.leshan.transport.javacoap.server.coaptcp.endpoint.JavaCoapsTcpServerEndpointsProvider;
import org.eclipse.leshan.transport.javacoap.server.endpoint.JavaCoapServerEndpointsProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -265,9 +266,16 @@ public static LeshanServer createLeshanServer(LeshanServerDemoCLI cli) throws Ex
JavaCoapTcpServerEndpointsProvider javacoapTcpEndpointsProvider = new JavaCoapTcpServerEndpointsProvider(
coapTcpAddr);

// Create CoAP over TLS endpoint based on java-coap
int coapsTcpPort = cli.main.jTlsLocalPort;
InetSocketAddress coapsTcpAddr = cli.main.jTlsLocalAddress == null ? new InetSocketAddress(coapsTcpPort)
: new InetSocketAddress(cli.main.jTlsLocalAddress, coapTcpPort);
JavaCoapsTcpServerEndpointsProvider javacoapsTcpEndpointsProvider = new JavaCoapsTcpServerEndpointsProvider(
coapsTcpAddr);

// Create LWM2M server
builder.setEndpointsProviders(endpointsBuilder.build(), javacoapEndpointsProvider,
javacoapTcpEndpointsProvider);
builder.setEndpointsProviders(endpointsBuilder.build(), javacoapEndpointsProvider, javacoapTcpEndpointsProvider,
javacoapsTcpEndpointsProvider);
return builder.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,19 @@ public static class ServerGeneralSection extends GeneralSection {
converter = PortConverter.class)
public Integer jTcpLocalPort = 5683;

@Option(names = { "-tsh", "--java-coaps-tcp-host" },
description = { //
"Set the local CoAP over TLS address of endpoint based on java-coap library.", //
"Default: any local address." })
public String jTlsLocalAddress;

@Option(names = { "-tsp", "--java-coaps-tcp-port" },
description = { //
"Set the local CoAP over TLS port of endpoint based on java-coap library.", //
"Default: ${DEFAULT-VALUE}" },
converter = PortConverter.class)
public Integer jTlsLocalPort = 5684;

@Option(names = { "-r", "--redis" },
description = { //
"Use redis to store registration and securityInfo.", //
Expand Down
Loading