Skip to content

Commit

Permalink
Cf-2.5.0 : remove deprecate usage of TrustedRpkStore/CertificateVerifier
Browse files Browse the repository at this point in the history
  • Loading branch information
sbernard31 committed Nov 19, 2020
1 parent caa03d1 commit 7970701
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 109 deletions.
Expand Up @@ -32,16 +32,10 @@
import org.eclipse.californium.elements.auth.RawPublicKeyIdentity;
import org.eclipse.californium.scandium.DTLSConnector;
import org.eclipse.californium.scandium.config.DtlsConnectorConfig.Builder;
import org.eclipse.californium.scandium.dtls.AlertMessage;
import org.eclipse.californium.scandium.dtls.AlertMessage.AlertDescription;
import org.eclipse.californium.scandium.dtls.AlertMessage.AlertLevel;
import org.eclipse.californium.scandium.dtls.CertificateMessage;
import org.eclipse.californium.scandium.dtls.DTLSSession;
import org.eclipse.californium.scandium.dtls.HandshakeException;
import org.eclipse.californium.scandium.dtls.cipher.CipherSuite;
import org.eclipse.californium.scandium.dtls.pskstore.AdvancedSinglePskStore;
import org.eclipse.californium.scandium.dtls.rpkstore.TrustedRpkStore;
import org.eclipse.californium.scandium.dtls.x509.CertificateVerifier;
import org.eclipse.californium.scandium.dtls.x509.NewAdvancedCertificateVerifier;
import org.eclipse.californium.scandium.dtls.x509.StaticNewAdvancedCertificateVerifier;
import org.eclipse.leshan.client.EndpointsManager;
import org.eclipse.leshan.client.servers.ServerIdentity;
import org.eclipse.leshan.client.servers.ServerIdentity.Role;
Expand Down Expand Up @@ -109,23 +103,9 @@ public synchronized ServerIdentity createEndpoint(ServerInfo serverInfo) {
newBuilder.setIdentity(serverInfo.privateKey, serverInfo.publicKey);
// set RPK truststore
final PublicKey expectedKey = serverInfo.serverPublicKey;
newBuilder.setRpkTrustStore(new TrustedRpkStore() {
@Override
public boolean isTrusted(RawPublicKeyIdentity id) {
PublicKey receivedKey = id.getKey();
if (receivedKey == null) {
LOG.warn("The server public key is null {}", id);
return false;
}
if (!receivedKey.equals(expectedKey)) {
LOG.debug(
"Server public key received does match with the expected one.\nReceived: {}\nExpected: {}",
receivedKey, expectedKey);
return false;
}
return true;
}
});
NewAdvancedCertificateVerifier rpkVerifier = new StaticNewAdvancedCertificateVerifier.Builder()
.setTrustedRPKs(new RawPublicKeyIdentity(expectedKey)).build();
newBuilder.setAdvancedCertificateVerifier(rpkVerifier);
serverIdentity = Identity.rpk(serverInfo.getAddress(), expectedKey);
filterCipherSuites(newBuilder, dtlsConfigbuilder.getIncompleteConfig().getSupportedCipherSuites(),
false, true);
Expand All @@ -134,43 +114,12 @@ public boolean isTrusted(RawPublicKeyIdentity id) {
newBuilder.setIdentity(serverInfo.privateKey, new Certificate[] { serverInfo.clientCertificate });

// set X509 verifier
final Certificate expectedServerCertificate = serverInfo.serverCertificate;
newBuilder.setCertificateVerifier(new CertificateVerifier() {

@Override
public void verifyCertificate(CertificateMessage message, DTLSSession session)
throws HandshakeException {
// As specify in the LWM2M spec 1.0, we only support "domain-issued certificate" usage
// Defined in : https://tools.ietf.org/html/rfc6698#section-2.1.1 (3 -- Certificate usage 3)

// Get server certificate from certificate message
if (message.getCertificateChain().getCertificates().size() == 0) {
AlertMessage alert = new AlertMessage(AlertLevel.FATAL, AlertDescription.BAD_CERTIFICATE,
session.getPeer());
throw new HandshakeException(
"Certificate chain could not be validated : server cert chain is empty", alert);
}
Certificate receivedServerCertificate = message.getCertificateChain().getCertificates().get(0);

// Validate certificate
if (!expectedServerCertificate.equals(receivedServerCertificate)) {
AlertMessage alert = new AlertMessage(AlertLevel.FATAL, AlertDescription.BAD_CERTIFICATE,
session.getPeer());
throw new HandshakeException(
"Certificate chain could not be validated: server certificate does not match expected one ('domain-issue certificate' usage)",
alert);
}
}

@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
});
serverIdentity = Identity.x509(serverInfo.getAddress(), EndpointContextUtil
.extractCN(((X509Certificate) expectedServerCertificate).getSubjectX500Principal().getName()));
filterCipherSuites(newBuilder,
dtlsConfigbuilder.getIncompleteConfig().getSupportedCipherSuites(), false, true);
newBuilder.setAdvancedCertificateVerifier(
new DefaultLeshanCertificateVerifier(serverInfo.serverCertificate));
serverIdentity = Identity.x509(serverInfo.getAddress(), EndpointContextUtil.extractCN(
((X509Certificate) serverInfo.serverCertificate).getSubjectX500Principal().getName()));
filterCipherSuites(newBuilder, dtlsConfigbuilder.getIncompleteConfig().getSupportedCipherSuites(),
false, true);
} else {
throw new RuntimeException("Unable to create connector : unsupported security mode");
}
Expand Down
@@ -0,0 +1,76 @@
package org.eclipse.leshan.client.californium;

import java.security.cert.Certificate;
import java.util.ArrayList;
import java.util.List;

import javax.security.auth.x500.X500Principal;

import org.eclipse.californium.scandium.dtls.AlertMessage;
import org.eclipse.californium.scandium.dtls.AlertMessage.AlertDescription;
import org.eclipse.californium.scandium.dtls.AlertMessage.AlertLevel;
import org.eclipse.californium.scandium.dtls.CertificateMessage;
import org.eclipse.californium.scandium.dtls.CertificateType;
import org.eclipse.californium.scandium.dtls.CertificateVerificationResult;
import org.eclipse.californium.scandium.dtls.ConnectionId;
import org.eclipse.californium.scandium.dtls.DTLSSession;
import org.eclipse.californium.scandium.dtls.HandshakeException;
import org.eclipse.californium.scandium.dtls.HandshakeResultHandler;
import org.eclipse.californium.scandium.dtls.x509.NewAdvancedCertificateVerifier;
import org.eclipse.californium.scandium.util.ServerNames;

public class DefaultLeshanCertificateVerifier implements NewAdvancedCertificateVerifier {

private final Certificate expectedServerCertificate;
private final List<CertificateType> supportedCertificateType;

public DefaultLeshanCertificateVerifier(Certificate expectedServerCertificate) {
this.expectedServerCertificate = expectedServerCertificate;
this.supportedCertificateType = new ArrayList<>(1);
this.supportedCertificateType.add(CertificateType.X_509);
}

@Override
public List<X500Principal> getAcceptedIssuers() {
return null;
}

@Override
public List<CertificateType> getSupportedCertificateType() {
return supportedCertificateType;
}

@Override
public CertificateVerificationResult verifyCertificate(ConnectionId cid, ServerNames serverName,
Boolean clientUsage, boolean truncateCertificatePath, CertificateMessage message, DTLSSession session) {
// As specify in the LWM2M spec 1.0, we only support "domain-issued certificate" usage
// Defined in : https://tools.ietf.org/html/rfc6698#section-2.1.1 (3 -- Certificate usage 3)

// Get server certificate from certificate message
if (message.getCertificateChain() == null || message.getCertificateChain().getCertificates().size() == 0) {
AlertMessage alert = new AlertMessage(AlertLevel.FATAL, AlertDescription.BAD_CERTIFICATE,
session.getPeer());
HandshakeException handshakeException = new HandshakeException(
"Certificate chain could not be validated : server cert chain is empty", alert);
return new CertificateVerificationResult(cid, handshakeException, null);
}
Certificate receivedServerCertificate = message.getCertificateChain().getCertificates().get(0);

// Validate certificate
if (!expectedServerCertificate.equals(receivedServerCertificate)) {
AlertMessage alert = new AlertMessage(AlertLevel.FATAL, AlertDescription.BAD_CERTIFICATE,
session.getPeer());
HandshakeException handshakeException = new HandshakeException(
"Certificate chain could not be validated: server certificate does not match expected one ('domain-issue certificate' usage)",
alert);
return new CertificateVerificationResult(cid, handshakeException, null);
}

return new CertificateVerificationResult(cid, message.getCertificateChain(), null);
}

@Override
public void setResultHandler(HandshakeResultHandler resultHandler) {
// we don't use async mode.
}
}
Expand Up @@ -34,6 +34,7 @@
import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
import org.eclipse.californium.scandium.config.DtlsConnectorConfig.Builder;
import org.eclipse.californium.scandium.dtls.CertificateType;
import org.eclipse.californium.scandium.dtls.x509.BridgeCertificateVerifier;
import org.eclipse.leshan.core.LwM2m;
import org.eclipse.leshan.core.californium.DefaultEndpointFactory;
import org.eclipse.leshan.core.californium.EndpointFactory;
Expand Down Expand Up @@ -401,6 +402,7 @@ public static NetworkConfig createDefaultNetworkConfig() {
* @return the LWM2M server.
* @throws IllegalStateException if builder configuration is not consistent.
*/
@SuppressWarnings("deprecation")
public LeshanServer build() {
if (localAddress == null)
localAddress = new InetSocketAddress(LwM2m.DEFAULT_COAP_PORT);
Expand Down Expand Up @@ -467,20 +469,6 @@ public LeshanServer build() {
if (incompleteConfig.getStaleConnectionThreshold() == null)
dtlsConfigBuilder.setStaleConnectionThreshold(coapConfig.getLong(Keys.MAX_PEER_INACTIVITY_PERIOD));

// handle trusted certificates
if (trustedCertificates != null) {
if (incompleteConfig.getCertificateVerifier() == null) {
if (incompleteConfig.getTrustStore() == null) {
dtlsConfigBuilder.setTrustStore(trustedCertificates);
} else if (!Arrays.equals(trustedCertificates, incompleteConfig.getTrustStore())) {
throw new IllegalStateException(String.format(
"Configuration conflict between LeshanBuilder and DtlsConnectorConfig.Builder for trusted Certificates (trustStore) : \n%s != \n%s",
Arrays.toString(trustedCertificates),
Arrays.toString(incompleteConfig.getTrustStore())));
}
}
}

// check conflict for private key
if (privateKey != null) {
if (incompleteConfig.getPrivateKey() != null && !incompleteConfig.getPrivateKey().equals(privateKey)) {
Expand All @@ -497,10 +485,6 @@ public LeshanServer build() {
publicKey, incompleteConfig.getPublicKey()));
}

// by default trust all RPK
if (incompleteConfig.getRpkTrustStore() == null) {
dtlsConfigBuilder.setRpkTrustAll();
}
dtlsConfigBuilder.setIdentity(privateKey, publicKey);
}
// if in X.509 mode set the private key, certificate chain, public key is extracted from the certificate
Expand All @@ -512,13 +496,47 @@ public LeshanServer build() {
Arrays.toString(certificateChain), incompleteConfig.getCertificateChain()));
}

// by default trust all RPK
if (incompleteConfig.getRpkTrustStore() == null) {
dtlsConfigBuilder.setRpkTrustAll();
}
dtlsConfigBuilder.setIdentity(privateKey, certificateChain, CertificateType.X_509,
CertificateType.RAW_PUBLIC_KEY);
}

// handle trusted certificates or RPK
if (incompleteConfig.getAdvancedCertificateVerifier() != null) {
if (trustedCertificates != null) {
throw new IllegalStateException(
"Configuration conflict between LeshanBuilder and DtlsConnectorConfig.Builder: if a AdvancedCertificateVerifier is set, trustedCertificates must not be set.");
}
} else {
BridgeCertificateVerifier.Builder verifierBuilder = new BridgeCertificateVerifier.Builder();
if (incompleteConfig.getRpkTrustStore() != null) {
verifierBuilder.setTrustedRPKs(incompleteConfig.getRpkTrustStore());
} else {
// by default trust all RPK
verifierBuilder.setTrustAllRPKs();
}
if (incompleteConfig.getTrustStore() != null) {
if (trustedCertificates != null
&& !Arrays.equals(trustedCertificates, incompleteConfig.getTrustStore())) {
throw new IllegalStateException(String.format(
"Configuration conflict between LeshanBuilder and DtlsConnectorConfig.Builder for trusted Certificates (trustStore) : \n%s != \n%s",
Arrays.toString(trustedCertificates),
Arrays.toString(incompleteConfig.getTrustStore())));
}
verifierBuilder.setTrustedCertificates(incompleteConfig.getTrustStore());
} else {
if (trustedCertificates != null) {
verifierBuilder.setTrustedCertificates(trustedCertificates);
}
}
if (incompleteConfig.getCertificateVerifier() != null) {
if (trustedCertificates != null) {
throw new IllegalStateException(
"Configuration conflict between LeshanBuilder and DtlsConnectorConfig.Builder: if a CertificateVerifier is set, trustedCertificates must not be set.");
}
verifierBuilder.setCertificateVerifier(incompleteConfig.getCertificateVerifier());
}
dtlsConfigBuilder.setAdvancedCertificateVerifier(verifierBuilder.build());
}
}

// Deactivate SNI by default
Expand Down

0 comments on commit 7970701

Please sign in to comment.