From b3d230b8893663a6baa2888ece8814889fc029de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vesa=20J=C3=A4=C3=A4skel=C3=A4inen?= Date: Fri, 23 Oct 2020 14:19:03 +0300 Subject: [PATCH 1/4] CertificateUsage: Add CertificateUsage type and initial support to client to configure it. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For now use LWM2M default mode domain issuer certificate (3). Signed-off-by: Vesa Jääskeläinen --- .../leshan/client/object/Security.java | 38 +++++++++++----- .../eclipse/leshan/core/CertificateUsage.java | 45 +++++++++++++++++++ .../java/org/eclipse/leshan/core/LwM2mId.java | 1 + .../tests/BootstrapIntegrationTestHelper.java | 2 +- 4 files changed, 75 insertions(+), 11 deletions(-) create mode 100644 leshan-core/src/main/java/org/eclipse/leshan/core/CertificateUsage.java diff --git a/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Security.java b/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Security.java index d85bc54a91..50f90acf18 100644 --- a/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Security.java +++ b/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Security.java @@ -23,6 +23,7 @@ import org.eclipse.leshan.client.resource.BaseInstanceEnabler; import org.eclipse.leshan.client.resource.LwM2mInstanceEnabler; import org.eclipse.leshan.client.servers.ServerIdentity; +import org.eclipse.leshan.core.CertificateUsage; import org.eclipse.leshan.core.SecurityMode; import org.eclipse.leshan.core.model.ObjectModel; import org.eclipse.leshan.core.model.ResourceModel.Type; @@ -30,6 +31,7 @@ import org.eclipse.leshan.core.response.ExecuteResponse; import org.eclipse.leshan.core.response.ReadResponse; import org.eclipse.leshan.core.response.WriteResponse; +import org.eclipse.leshan.core.util.datatype.ULong; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -41,7 +43,8 @@ public class Security extends BaseInstanceEnabler { private static final Logger LOG = LoggerFactory.getLogger(Security.class); private final static List supportedResources = Arrays.asList(SEC_SERVER_URI, SEC_BOOTSTRAP, - SEC_SECURITY_MODE, SEC_PUBKEY_IDENTITY, SEC_SERVER_PUBKEY, SEC_SECRET_KEY, SEC_SERVER_ID); + SEC_SECURITY_MODE, SEC_PUBKEY_IDENTITY, SEC_SERVER_PUBKEY, SEC_SECRET_KEY, SEC_SERVER_ID, + SEC_CERTIFICATE_USAGE); private String serverUri; /* coaps://host:port */ private boolean bootstrapServer; @@ -53,12 +56,15 @@ public class Security extends BaseInstanceEnabler { private Integer shortServerId; + private ULong certificateUsage; + public Security() { // should only be used at bootstrap time + this.certificateUsage = CertificateUsage.DOMAIN_ISSUER_CERTIFICATE.code; } public Security(String serverUri, boolean bootstrapServer, int securityMode, byte[] publicKeyOrIdentity, - byte[] serverPublicKey, byte[] secretKey, Integer shortServerId) { + byte[] serverPublicKey, byte[] secretKey, Integer shortServerId, ULong certificateUsage) { this.serverUri = serverUri; this.bootstrapServer = bootstrapServer; this.securityMode = securityMode; @@ -66,13 +72,15 @@ public Security(String serverUri, boolean bootstrapServer, int securityMode, byt this.serverPublicKey = serverPublicKey; this.secretKey = secretKey; this.shortServerId = shortServerId; + this.certificateUsage = certificateUsage; } /** * Returns a new security instance (NoSec) for a bootstrap server. */ public static Security noSecBootstap(String serverUri) { - return new Security(serverUri, true, SecurityMode.NO_SEC.code, new byte[0], new byte[0], new byte[0], 0); + return new Security(serverUri, true, SecurityMode.NO_SEC.code, new byte[0], new byte[0], new byte[0], 0, + CertificateUsage.DOMAIN_ISSUER_CERTIFICATE.code); } /** @@ -80,7 +88,7 @@ public static Security noSecBootstap(String serverUri) { */ public static Security pskBootstrap(String serverUri, byte[] pskIdentity, byte[] privateKey) { return new Security(serverUri, true, SecurityMode.PSK.code, pskIdentity.clone(), new byte[0], - privateKey.clone(), 0); + privateKey.clone(), 0, CertificateUsage.DOMAIN_ISSUER_CERTIFICATE.code); } /** @@ -89,7 +97,7 @@ public static Security pskBootstrap(String serverUri, byte[] pskIdentity, byte[] public static Security rpkBootstrap(String serverUri, byte[] clientPublicKey, byte[] clientPrivateKey, byte[] serverPublicKey) { return new Security(serverUri, true, SecurityMode.RPK.code, clientPublicKey.clone(), serverPublicKey.clone(), - clientPrivateKey.clone(), 0); + clientPrivateKey.clone(), 0, CertificateUsage.DOMAIN_ISSUER_CERTIFICATE.code); } /** @@ -98,7 +106,7 @@ public static Security rpkBootstrap(String serverUri, byte[] clientPublicKey, by public static Security x509Bootstrap(String serverUri, byte[] clientCertificate, byte[] clientPrivateKey, byte[] serverPublicKey) { return new Security(serverUri, true, SecurityMode.X509.code, clientCertificate.clone(), serverPublicKey.clone(), - clientPrivateKey.clone(), 0); + clientPrivateKey.clone(), 0, CertificateUsage.DOMAIN_ISSUER_CERTIFICATE.code); } /** @@ -106,7 +114,7 @@ public static Security x509Bootstrap(String serverUri, byte[] clientCertificate, */ public static Security noSec(String serverUri, int shortServerId) { return new Security(serverUri, false, SecurityMode.NO_SEC.code, new byte[0], new byte[0], new byte[0], - shortServerId); + shortServerId, CertificateUsage.DOMAIN_ISSUER_CERTIFICATE.code); } /** @@ -114,7 +122,7 @@ public static Security noSec(String serverUri, int shortServerId) { */ public static Security psk(String serverUri, int shortServerId, byte[] pskIdentity, byte[] privateKey) { return new Security(serverUri, false, SecurityMode.PSK.code, pskIdentity.clone(), new byte[0], - privateKey.clone(), shortServerId); + privateKey.clone(), shortServerId, CertificateUsage.DOMAIN_ISSUER_CERTIFICATE.code); } /** @@ -123,7 +131,7 @@ public static Security psk(String serverUri, int shortServerId, byte[] pskIdenti public static Security rpk(String serverUri, int shortServerId, byte[] clientPublicKey, byte[] clientPrivateKey, byte[] serverPublicKey) { return new Security(serverUri, false, SecurityMode.RPK.code, clientPublicKey.clone(), serverPublicKey.clone(), - clientPrivateKey.clone(), shortServerId); + clientPrivateKey.clone(), shortServerId, CertificateUsage.DOMAIN_ISSUER_CERTIFICATE.code); } /** @@ -132,7 +140,8 @@ public static Security rpk(String serverUri, int shortServerId, byte[] clientPub public static Security x509(String serverUri, int shortServerId, byte[] clientCertificate, byte[] clientPrivateKey, byte[] serverPublicKey) { return new Security(serverUri, false, SecurityMode.X509.code, clientCertificate.clone(), - serverPublicKey.clone(), clientPrivateKey.clone(), shortServerId); + serverPublicKey.clone(), clientPrivateKey.clone(), shortServerId, + CertificateUsage.DOMAIN_ISSUER_CERTIFICATE.code); } @Override @@ -186,6 +195,12 @@ public WriteResponse write(ServerIdentity identity, int resourceId, LwM2mResourc } shortServerId = ((Long) value.getValue()).intValue(); return WriteResponse.success(); + case SEC_CERTIFICATE_USAGE: // certificate usage + if (value.getType() != Type.UNSIGNED_INTEGER) { + return WriteResponse.badRequest("invalid type"); + } + certificateUsage = (ULong) value.getValue(); + return WriteResponse.success(); default: return super.write(identity, resourceId, value); @@ -219,6 +234,9 @@ public ReadResponse read(ServerIdentity identity, int resourceid) { case SEC_SERVER_ID: // short server id return ReadResponse.success(resourceid, shortServerId); + case SEC_CERTIFICATE_USAGE: // certificate usage + return ReadResponse.success(resourceid, certificateUsage); + default: return super.read(identity, resourceid); } diff --git a/leshan-core/src/main/java/org/eclipse/leshan/core/CertificateUsage.java b/leshan-core/src/main/java/org/eclipse/leshan/core/CertificateUsage.java new file mode 100644 index 0000000000..242a5b399e --- /dev/null +++ b/leshan-core/src/main/java/org/eclipse/leshan/core/CertificateUsage.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2020 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; + +import org.eclipse.leshan.core.util.datatype.ULong; + +/** + * For details about Certificate Usage please see: + * rfc6698#section-2.1.1 - The Certificate Usage Field + */ +public enum CertificateUsage { + CA_CONSTRAINT(0), SERVICE_CERTIFICATE_CONSTRAINT(1), TRUST_ANCHOR_ASSERTION(2), DOMAIN_ISSUER_CERTIFICATE(3); + + public final ULong code; + + private CertificateUsage(int code) { + this.code = ULong.valueOf(code); + } + + public static CertificateUsage fromCode(int code) { + return fromCode(ULong.valueOf(code)); + } + + public static CertificateUsage fromCode(ULong code) { + for (CertificateUsage sm : CertificateUsage.values()) { + if (sm.code.equals(code)) { + return sm; + } + } + throw new IllegalArgumentException(String.format("Unsupported certificate usage code : %s", code)); + } +} diff --git a/leshan-core/src/main/java/org/eclipse/leshan/core/LwM2mId.java b/leshan-core/src/main/java/org/eclipse/leshan/core/LwM2mId.java index 392df7d8f6..9696245df7 100644 --- a/leshan-core/src/main/java/org/eclipse/leshan/core/LwM2mId.java +++ b/leshan-core/src/main/java/org/eclipse/leshan/core/LwM2mId.java @@ -41,6 +41,7 @@ public interface LwM2mId { public static final int SEC_SERVER_PUBKEY = 4; public static final int SEC_SECRET_KEY = 5; public static final int SEC_SERVER_ID = 10; + public static final int SEC_CERTIFICATE_USAGE = 15; /* SERVER RESOURCES */ diff --git a/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/BootstrapIntegrationTestHelper.java b/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/BootstrapIntegrationTestHelper.java index 0069c7c26e..7a6be8e28f 100644 --- a/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/BootstrapIntegrationTestHelper.java +++ b/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/BootstrapIntegrationTestHelper.java @@ -188,7 +188,7 @@ public Security withoutSecurity() { // Create Security Object (with bootstrap server only) String bsUrl = "coap://" + bootstrapServer.getUnsecuredAddress().getHostString() + ":" + bootstrapServer.getUnsecuredAddress().getPort(); - return new Security(bsUrl, true, 3, new byte[0], new byte[0], new byte[0], 0); + return Security.noSecBootstap(bsUrl); } @Override From 6e96cee3e69ae7c6922946b56c88e1c2a868ff30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vesa=20J=C3=A4=C3=A4skel=C3=A4inen?= Date: Tue, 20 Oct 2020 18:21:44 +0300 Subject: [PATCH 2/4] CertificateUsage: Add CertificateUsage support to client. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Vesa Jääskeläinen Also-by: Simon Bernard --- .../californium/BaseCertificateVerifier.java | 115 ++++++++++++++++ .../CaConstraintCertificateVerifier.java | 100 ++++++++++++++ .../CaliforniumEndpointsManager.java | 64 ++++++++- .../DomainIssuerCertificateVerifier.java | 81 ++++++++++++ ...tificateConstraintCertificateVerifier.java | 96 ++++++++++++++ ...ustAnchorAssertionCertificateVerifier.java | 86 ++++++++++++ .../leshan/client/californium/X509Util.java | 125 ++++++++++++++++++ .../leshan/client/object/Security.java | 9 ++ .../leshan/client/servers/ServerInfo.java | 2 + .../client/servers/ServersInfoExtractor.java | 8 ++ .../credentials/clientKeyStore.jks | Bin 2791 -> 3548 bytes .../credentials/generate_credentials.sh | 4 +- .../credentials/serverKeyStore.jks | Bin 2542 -> 3352 bytes 13 files changed, 685 insertions(+), 5 deletions(-) create mode 100644 leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/BaseCertificateVerifier.java create mode 100644 leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/CaConstraintCertificateVerifier.java create mode 100644 leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/DomainIssuerCertificateVerifier.java create mode 100644 leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/ServiceCertificateConstraintCertificateVerifier.java create mode 100644 leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/TrustAnchorAssertionCertificateVerifier.java create mode 100644 leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/X509Util.java diff --git a/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/BaseCertificateVerifier.java b/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/BaseCertificateVerifier.java new file mode 100644 index 0000000000..0f9655ad94 --- /dev/null +++ b/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/BaseCertificateVerifier.java @@ -0,0 +1,115 @@ +/******************************************************************************* + * Copyright (c) 2020 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.client.californium; + +import java.net.InetSocketAddress; +import java.security.cert.CertPath; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.util.Arrays; +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; +import org.eclipse.leshan.core.util.X509CertUtil; + +public abstract class BaseCertificateVerifier implements NewAdvancedCertificateVerifier { + + private final List supportedCertificateType = Arrays.asList(CertificateType.X_509); + + @Override + public List getSupportedCertificateType() { + return supportedCertificateType; + } + + @Override + public void setResultHandler(HandshakeResultHandler resultHandler) { + // we don't use async mode. + } + + @Override + public List getAcceptedIssuers() { + return null; + } + + @Override + public CertificateVerificationResult verifyCertificate(ConnectionId cid, ServerNames serverName, + Boolean clientUsage, boolean truncateCertificatePath, CertificateMessage message, DTLSSession session) { + try { + CertPath validatedCertPath = verifyCertificate(clientUsage, message, session); + return new CertificateVerificationResult(cid, validatedCertPath, null); + } catch (HandshakeException exception) { + return new CertificateVerificationResult(cid, exception, null); + } + } + + protected abstract CertPath verifyCertificate(Boolean clientUsage, CertificateMessage message, DTLSSession session) + throws HandshakeException; + + /** + * Ensure that chain is not empty + */ + protected void validateCertificateChainNotEmpty(CertPath certChain, InetSocketAddress foreignPeerAddress) + throws HandshakeException { + if (certChain.getCertificates().size() == 0) { + AlertMessage alert = new AlertMessage(AlertLevel.FATAL, AlertDescription.BAD_CERTIFICATE, + foreignPeerAddress); + throw new HandshakeException("Certificate chain could not be validated : server cert chain is empty", + alert); + } + } + + /** + * Ensure that received certificate is x509 certificate + */ + protected X509Certificate validateReceivedCertificateIsSupported(CertPath certChain, + InetSocketAddress foreignPeerAddress) throws HandshakeException { + Certificate receivedServerCertificate = certChain.getCertificates().get(0); + if (!(receivedServerCertificate instanceof X509Certificate)) { + AlertMessage alert = new AlertMessage(AlertLevel.FATAL, AlertDescription.UNSUPPORTED_CERTIFICATE, + foreignPeerAddress); + throw new HandshakeException("Certificate chain could not be validated - unknown certificate type", alert); + } + return (X509Certificate) receivedServerCertificate; + } + + protected void validateSubject(final DTLSSession session, final X509Certificate receivedServerCertificate) + throws HandshakeException { + final InetSocketAddress peerSocket = session.getPeer(); + + if (X509CertUtil.matchSubjectDnsName(receivedServerCertificate, peerSocket.getHostName())) + return; + + if (X509CertUtil.matchSubjectInetAddress(receivedServerCertificate, peerSocket.getAddress())) + return; + + AlertMessage alert = new AlertMessage(AlertLevel.FATAL, AlertDescription.BAD_CERTIFICATE, session.getPeer()); + throw new HandshakeException( + "Certificate chain could not be validated - server identity does not match certificate", alert); + } +} diff --git a/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/CaConstraintCertificateVerifier.java b/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/CaConstraintCertificateVerifier.java new file mode 100644 index 0000000000..dc08211dcf --- /dev/null +++ b/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/CaConstraintCertificateVerifier.java @@ -0,0 +1,100 @@ +/******************************************************************************* + * Copyright (c) 2020 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.client.californium; + +import java.security.GeneralSecurityException; +import java.security.cert.CertPath; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; + +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.leshan.core.util.Validate; + +/** + * This class implements Certificate Usage (0) - CA Constraint + * + * From RFC 6698: + * + *
+ * 0 -- Certificate usage 0 is used to specify a CA certificate, or
+ *       the public key of such a certificate, that MUST be found in any of
+ *       the PKIX certification paths for the end entity certificate given
+ *       by the server in TLS.  This certificate usage is sometimes
+ *       referred to as "CA constraint" because it limits which CA can be
+ *       used to issue certificates for a given service on a host.  The
+ *       presented certificate MUST pass PKIX certification path
+ *       validation, and a CA certificate that matches the TLSA record MUST
+ *       be included as part of a valid certification path.  Because this
+ *       certificate usage allows both trust anchors and CA certificates,
+ *       the certificate might or might not have the basicConstraints
+ *       extension present.
+ * 
+ * + * For details about Certificate Usage please see: + * rfc6698#section-2.1.1 - The Certificate Usage Field + */ +public class CaConstraintCertificateVerifier extends BaseCertificateVerifier { + + private final Certificate caCertificate; + private final X509Certificate[] trustedCertificates; + + public CaConstraintCertificateVerifier(Certificate caCertificate, X509Certificate[] trustedCertificates) { + Validate.notNull(caCertificate); + Validate.notNull(trustedCertificates); + Validate.notEmpty(trustedCertificates); + this.caCertificate = caCertificate; + this.trustedCertificates = trustedCertificates; + } + + @Override + public CertPath verifyCertificate(Boolean clientUsage, CertificateMessage message, DTLSSession session) + throws HandshakeException { + CertPath messageChain = message.getCertificateChain(); + + validateCertificateChainNotEmpty(messageChain, session.getPeer()); + X509Certificate receivedServerCertificate = validateReceivedCertificateIsSupported(messageChain, + session.getPeer()); + + // - must do PKIX validation with trustStore + CertPath certPath; + try { + certPath = X509Util.applyPKIXValidation(messageChain, trustedCertificates); + } catch (GeneralSecurityException e) { + AlertMessage alert = new AlertMessage(AlertLevel.FATAL, AlertDescription.BAD_CERTIFICATE, + session.getPeer()); + throw new HandshakeException("Certificate chain could not be validated", alert, e); + } + + // - must check that given certificate is part of certPath + if (!certPath.getCertificates().contains(caCertificate)) { + // No match found -> throw exception about it + AlertMessage alert = new AlertMessage(AlertLevel.FATAL, AlertDescription.BAD_CERTIFICATE, + session.getPeer()); + throw new HandshakeException("Certificate chain could not be validated", alert); + } + + // - validate server name + validateSubject(session, receivedServerCertificate); + + return certPath; + } + +} diff --git a/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/CaliforniumEndpointsManager.java b/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/CaliforniumEndpointsManager.java index 0c3b1d8d0d..d0f4dfb55e 100644 --- a/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/CaliforniumEndpointsManager.java +++ b/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/CaliforniumEndpointsManager.java @@ -30,6 +30,7 @@ import org.eclipse.californium.core.network.config.NetworkConfig; import org.eclipse.californium.elements.Connector; import org.eclipse.californium.elements.auth.RawPublicKeyIdentity; +import org.eclipse.californium.elements.util.CertPathUtil; import org.eclipse.californium.scandium.DTLSConnector; import org.eclipse.californium.scandium.config.DtlsConnectorConfig.Builder; import org.eclipse.californium.scandium.dtls.cipher.CipherSuite; @@ -40,6 +41,7 @@ import org.eclipse.leshan.client.servers.ServerIdentity; import org.eclipse.leshan.client.servers.ServerIdentity.Role; import org.eclipse.leshan.client.servers.ServerInfo; +import org.eclipse.leshan.core.CertificateUsage; import org.eclipse.leshan.core.SecurityMode; import org.eclipse.leshan.core.californium.EndpointContextUtil; import org.eclipse.leshan.core.californium.EndpointFactory; @@ -123,9 +125,65 @@ public synchronized ServerIdentity createEndpoint(ServerInfo serverInfo) { // set identity newBuilder.setIdentity(serverInfo.privateKey, new Certificate[] { serverInfo.clientCertificate }); - // set X509 verifier - newBuilder.setAdvancedCertificateVerifier( - new DefaultLeshanCertificateVerifier(serverInfo.serverCertificate)); + // LWM2M v1.1.1 - 5.2.8.7. Certificate Usage Field + // + // 0: Certificate usage 0 ("CA constraint") + // - trustStore is combination of client's configured trust store and provided certificate in server + // info + // - must do PKIX validation with trustStore to build certPath + // - must check that given certificate is part of certPath + // - validate server name + // + // 1: Certificate usage 1 ("service certificate constraint") + // - trustStore is client's configured trust store + // - must do PKIX validation with trustStore + // - target certificate must match what is provided certificate in server info + // - validate server name + // + // 2: Certificate usage 2 ("trust anchor assertion") + // - trustStore is only the provided certificate in server info + // - must do PKIX validation with trustStore + // - validate server name + // + // 3: Certificate usage 3 ("domain-issued certificate") (default mode if missing) + // - no trustStore used in this mode + // - target certificate must match what is provided certificate in server info + // - validate server name + + CertificateUsage certificateUsage = serverInfo.certificateUsage != null ? serverInfo.certificateUsage + : CertificateUsage.DOMAIN_ISSUER_CERTIFICATE; + + if (certificateUsage == CertificateUsage.CA_CONSTRAINT) { + X509Certificate[] trustedCertificates = null; + // - trustStore is combination of client's configured trust store and provided certificate in server + // info + ArrayList newTrustedCertificatesList = new ArrayList<>(); + if (this.trustStore != null) { + newTrustedCertificatesList.addAll(CertPathUtil.toX509CertificatesList(this.trustStore)); + } + newTrustedCertificatesList.add((X509Certificate) serverInfo.serverCertificate); + trustedCertificates = newTrustedCertificatesList.toArray(new X509Certificate[0]); + newBuilder.setAdvancedCertificateVerifier( + new CaConstraintCertificateVerifier(serverInfo.serverCertificate, trustedCertificates)); + } else if (certificateUsage == CertificateUsage.SERVICE_CERTIFICATE_CONSTRAINT) { + X509Certificate[] trustedCertificates = null; + + // - trustStore is client's configured trust store + if (this.trustStore != null) { + trustedCertificates = CertPathUtil.toX509CertificatesList(this.trustStore) + .toArray(new X509Certificate[0]); + } + + newBuilder.setAdvancedCertificateVerifier(new ServiceCertificateConstraintCertificateVerifier( + serverInfo.serverCertificate, trustedCertificates)); + } else if (certificateUsage == CertificateUsage.TRUST_ANCHOR_ASSERTION) { + newBuilder.setAdvancedCertificateVerifier(new TrustAnchorAssertionCertificateVerifier( + (X509Certificate) serverInfo.serverCertificate)); + } else if (certificateUsage == CertificateUsage.DOMAIN_ISSUER_CERTIFICATE) { + newBuilder.setAdvancedCertificateVerifier( + new DomainIssuerCertificateVerifier(serverInfo.serverCertificate)); + } + serverIdentity = Identity.x509(serverInfo.getAddress(), EndpointContextUtil.extractCN( ((X509Certificate) serverInfo.serverCertificate).getSubjectX500Principal().getName())); filterCipherSuites(newBuilder, dtlsConfigbuilder.getIncompleteConfig().getSupportedCipherSuites(), diff --git a/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/DomainIssuerCertificateVerifier.java b/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/DomainIssuerCertificateVerifier.java new file mode 100644 index 0000000000..4c9e949490 --- /dev/null +++ b/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/DomainIssuerCertificateVerifier.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2020 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.client.californium; + +import java.security.cert.CertPath; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; + +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.leshan.core.util.Validate; + +/** + * This class implements Certificate Usage (3) - Domain Issuer Certificate + * + * From RFC 6698: + * + *
+ * 3 -- Certificate usage 3 is used to specify a certificate, or the
+ *       public key of such a certificate, that MUST match the end entity
+ *       certificate given by the server in TLS.  This certificate usage is
+ *       sometimes referred to as "domain-issued certificate" because it
+ *       allows for a domain name administrator to issue certificates for a
+ *       domain without involving a third-party CA.  The target certificate
+ *       MUST match the TLSA record.  The difference between certificate
+ *       usage 1 and certificate usage 3 is that certificate usage 1
+ *       requires that the certificate pass PKIX validation, but PKIX
+ *       validation is not tested for certificate usage 3.
+ * 
+ * + * For details about Certificate Usage please see: + * rfc6698#section-2.1.1 - The Certificate Usage Field + */ +public class DomainIssuerCertificateVerifier extends BaseCertificateVerifier { + private final Certificate domainIssuerCertificate; + + public DomainIssuerCertificateVerifier(Certificate domainIssuerCertificate) { + Validate.notNull(domainIssuerCertificate); + this.domainIssuerCertificate = domainIssuerCertificate; + } + + @Override + public CertPath verifyCertificate(Boolean clientUsage, CertificateMessage message, DTLSSession session) + throws HandshakeException { + CertPath messageChain = message.getCertificateChain(); + + validateCertificateChainNotEmpty(messageChain, session.getPeer()); + + X509Certificate receivedServerCertificate = validateReceivedCertificateIsSupported(messageChain, + session.getPeer()); + + // - target certificate must match what is provided certificate in server info + if (!domainIssuerCertificate.equals(receivedServerCertificate)) { + AlertMessage alert = new AlertMessage(AlertLevel.FATAL, AlertDescription.BAD_CERTIFICATE, + session.getPeer()); + throw new HandshakeException("Certificate chain could not be validated", alert); + } + + // - validate server name + validateSubject(session, receivedServerCertificate); + + return messageChain; + } +} diff --git a/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/ServiceCertificateConstraintCertificateVerifier.java b/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/ServiceCertificateConstraintCertificateVerifier.java new file mode 100644 index 0000000000..4b75b0530a --- /dev/null +++ b/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/ServiceCertificateConstraintCertificateVerifier.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2020 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.client.californium; + +import java.security.GeneralSecurityException; +import java.security.cert.CertPath; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; + +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.leshan.core.util.Validate; + +/** + * This class implements Certificate Usage (1) - Service Certificate Constraint + * + * From RFC 6698: + * + *
+ * 1 -- Certificate usage 1 is used to specify an end entity
+ *       certificate, or the public key of such a certificate, that MUST be
+ *       matched with the end entity certificate given by the server in
+ *       TLS.  This certificate usage is sometimes referred to as "service
+ *       certificate constraint" because it limits which end entity
+ *       certificate can be used by a given service on a host.  The target
+ *       certificate MUST pass PKIX certification path validation and MUST
+ *       match the TLSA record.
+ * 
+ * + * For details about Certificate Usage please see: + * rfc6698#section-2.1.1 - The Certificate Usage Field + */ +public class ServiceCertificateConstraintCertificateVerifier extends BaseCertificateVerifier { + + private final Certificate serviceCertificate; + private final X509Certificate[] trustedCertificates; + + public ServiceCertificateConstraintCertificateVerifier(Certificate serviceCertificate, + X509Certificate[] trustedCertificates) { + Validate.notNull(serviceCertificate); + Validate.notNull(trustedCertificates); + Validate.notEmpty(trustedCertificates); + this.serviceCertificate = serviceCertificate; + this.trustedCertificates = trustedCertificates; + } + + @Override + public CertPath verifyCertificate(Boolean clientUsage, CertificateMessage message, DTLSSession session) + throws HandshakeException { + CertPath messageChain = message.getCertificateChain(); + + validateCertificateChainNotEmpty(messageChain, session.getPeer()); + + X509Certificate receivedServerCertificate = validateReceivedCertificateIsSupported(messageChain, + session.getPeer()); + + // - must do PKIX validation with trustStore + CertPath certPath; + try { + certPath = X509Util.applyPKIXValidation(messageChain, trustedCertificates); + } catch (GeneralSecurityException e) { + AlertMessage alert = new AlertMessage(AlertLevel.FATAL, AlertDescription.BAD_CERTIFICATE, + session.getPeer()); + throw new HandshakeException("Certificate chain could not be validated", alert, e); + } + + // - target certificate must match what is provided certificate in server info + if (!serviceCertificate.equals(receivedServerCertificate)) { + AlertMessage alert = new AlertMessage(AlertLevel.FATAL, AlertDescription.BAD_CERTIFICATE, + session.getPeer()); + throw new HandshakeException("Certificate chain could not be validated", alert); + } + + // - validate server name + validateSubject(session, receivedServerCertificate); + + return certPath; + } +} diff --git a/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/TrustAnchorAssertionCertificateVerifier.java b/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/TrustAnchorAssertionCertificateVerifier.java new file mode 100644 index 0000000000..4aba4a7797 --- /dev/null +++ b/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/TrustAnchorAssertionCertificateVerifier.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright (c) 2020 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.client.californium; + +import java.security.GeneralSecurityException; +import java.security.cert.CertPath; +import java.security.cert.X509Certificate; + +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.leshan.core.util.Validate; + +/** + * This class implements Certificate Usage (2) - Trust Anchor Assertion + * + * From RFC 6698: + * + *
+ * 2 -- Certificate usage 2 is used to specify a certificate, or the
+ *       public key of such a certificate, that MUST be used as the trust
+ *       anchor when validating the end entity certificate given by the
+ *       server in TLS.  This certificate usage is sometimes referred to as
+ *       "trust anchor assertion" and allows a domain name administrator to
+ *       specify a new trust anchor -- for example, if the domain issues
+ *       its own certificates under its own CA that is not expected to be
+ *       in the end users' collection of trust anchors.  The target
+ *       certificate MUST pass PKIX certification path validation, with any
+ *       certificate matching the TLSA record considered to be a trust
+ *       anchor for this certification path validation.
+ * 
+ * + * For details about Certificate Usage please see: + * rfc6698#section-2.1.1 - The Certificate Usage Field + */ +public class TrustAnchorAssertionCertificateVerifier extends BaseCertificateVerifier { + + private final X509Certificate[] trustAnchor; + + public TrustAnchorAssertionCertificateVerifier(X509Certificate trustAnchor) { + Validate.notNull(trustAnchor); + this.trustAnchor = new X509Certificate[] { trustAnchor }; + } + + @Override + public CertPath verifyCertificate(Boolean clientUsage, CertificateMessage message, DTLSSession session) + throws HandshakeException { + CertPath messageChain = message.getCertificateChain(); + + validateCertificateChainNotEmpty(messageChain, session.getPeer()); + X509Certificate receivedServerCertificate = validateReceivedCertificateIsSupported(messageChain, + session.getPeer()); + + // - must do PKIX validation with trustStore + CertPath certPath; + try { + certPath = X509Util.applyPKIXValidation(messageChain, trustAnchor); + } catch (GeneralSecurityException e) { + 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); + } + + // - validate server name + validateSubject(session, receivedServerCertificate); + + return certPath; + } +} diff --git a/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/X509Util.java b/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/X509Util.java new file mode 100644 index 0000000000..7c207dc68a --- /dev/null +++ b/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/X509Util.java @@ -0,0 +1,125 @@ +/******************************************************************************* + * Copyright (c) 2020 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.client.californium; + +import java.security.GeneralSecurityException; +import java.security.cert.CertPath; +import java.security.cert.CertPathValidator; +import java.security.cert.CertPathValidatorResult; +import java.security.cert.CertificateEncodingException; +import java.security.cert.PKIXCertPathValidatorResult; +import java.security.cert.PKIXParameters; +import java.security.cert.TrustAnchor; +import java.security.cert.X509Certificate; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.eclipse.californium.elements.util.CertPathUtil; + +public class X509Util { + + /** + * Validate Certificate Path using Java + * PKIX algorithm which implement RFC3280. + * + * @param certPath a certificate path to validate + * @param trustedCertificates list of trusted certificates + * @return the certpath from certificate to validate (end node) to first trusted anchor included. + */ + public static CertPath applyPKIXValidation(CertPath certPath, X509Certificate[] trustedCertificates) + throws GeneralSecurityException { + // We first need to adapt certificate path to PKIX algorithm : + // - trust anchor must not be in certificate path + // See : https://tools.ietf.org/html/rfc3280#section-6 + CertPath adaptedCertPath = truncateToFirstTrustedCert(certPath, trustedCertificates); + + if (adaptedCertPath.getCertificates().isEmpty()) + throw new IllegalArgumentException( + "Invalid certificate path : certificate path is empty or end node certificate is directly trusted"); + + // Create trustAnchor for PKIX algorithm + Set trustAnchors = new HashSet(); + for (X509Certificate cert : trustedCertificates) { + trustAnchors.add(new TrustAnchor(cert, null)); + } + + // Apply PKIX Validation agorithm + String algorithm = CertPathValidator.getDefaultType(); + CertPathValidator validator = CertPathValidator.getInstance(algorithm); + PKIXParameters params = new PKIXParameters(trustAnchors); + // TODO: implement alternative means of revocation checking ? + params.setRevocationEnabled(false); + CertPathValidatorResult result = validator.validate(adaptedCertPath, params); + + // Create complete validated certification path + X509Certificate trustedCertificate = ((PKIXCertPathValidatorResult) result).getTrustAnchor().getTrustedCert(); + return add(adaptedCertPath, trustedCertificate); + } + + /** + * Truncate certificate path just before the first trusted certificates. + * + * @param certPath a certificate path to eventually truncate + * @param trustedCertificates list of trusted certificates + * @return a certPath without trusted any trusted certificates + * @throws CertificateEncodingException + */ + public static CertPath truncateToFirstTrustedCert(CertPath certPath, X509Certificate[] trustedCertificates) + throws CertificateEncodingException { + List certificates = CertPathUtil.toX509CertificatesList(certPath.getCertificates()); + for (int index = 0; index < certificates.size(); ++index) { + X509Certificate certificate = certificates.get(index); + if (contains(certificate, trustedCertificates)) { + return CertPathUtil.generateCertPath(certificates, index); + } + } + return certPath; + } + + /** + * Add certificate at the end of the given certificate path. + * + * @param certPath a certificate path to extend + * @param certificate to add at the end + * @return a certPath ending with given certificate + * @throws CertificateEncodingException + */ + public static CertPath add(CertPath certPath, X509Certificate certificate) throws CertificateEncodingException { + List certificates = CertPathUtil.toX509CertificatesList(certPath.getCertificates()); + certificates.add(certificate); + return CertPathUtil.generateCertPath(certificates); + } + + /** + * Search certificate in trusts. + * + * @param certificate certificate to search + * @param certificates to search + * @return {@code true}, if certificate is contained, {@code false}, otherwise. + * @throws CertificateEncodingException if encoding a certificate failed! + */ + public static boolean contains(X509Certificate certificate, X509Certificate[] certificates) + throws CertificateEncodingException { + for (X509Certificate trust : certificates) { + if (certificate.equals(trust)) { + return true; + } + } + return false; + } +} diff --git a/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Security.java b/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Security.java index 50f90acf18..39bfe91611 100644 --- a/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Security.java +++ b/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Security.java @@ -144,6 +144,15 @@ public static Security x509(String serverUri, int shortServerId, byte[] clientCe CertificateUsage.DOMAIN_ISSUER_CERTIFICATE.code); } + /** + * Returns a new security instance (X509) for a device management server. + */ + public static Security x509(String serverUri, int shortServerId, byte[] clientCertificate, byte[] clientPrivateKey, + byte[] serverPublicKey, ULong certificateUsage) { + return new Security(serverUri, false, SecurityMode.X509.code, clientCertificate.clone(), + serverPublicKey.clone(), clientPrivateKey.clone(), shortServerId, certificateUsage); + } + @Override public WriteResponse write(ServerIdentity identity, int resourceId, LwM2mResource value) { if (!identity.isSystem()) diff --git a/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServerInfo.java b/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServerInfo.java index 06d2d99204..a53e0b9f0c 100644 --- a/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServerInfo.java +++ b/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServerInfo.java @@ -22,6 +22,7 @@ import java.security.PublicKey; import java.security.cert.Certificate; +import org.eclipse.leshan.core.CertificateUsage; import org.eclipse.leshan.core.LwM2m; import org.eclipse.leshan.core.SecurityMode; import org.slf4j.Logger; @@ -40,6 +41,7 @@ public class ServerInfo { public boolean bootstrap = false; public URI serverUri; public SecurityMode secureMode; + public CertificateUsage certificateUsage; public String pskId; public byte[] pskKey; diff --git a/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java b/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java index 6383f83508..7e38f731dc 100644 --- a/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java +++ b/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java @@ -38,6 +38,7 @@ import org.eclipse.leshan.client.resource.LwM2mInstanceEnabler; import org.eclipse.leshan.client.resource.LwM2mObjectEnabler; +import org.eclipse.leshan.core.CertificateUsage; import org.eclipse.leshan.core.LwM2mId; import org.eclipse.leshan.core.SecurityMode; import org.eclipse.leshan.core.node.LwM2mObject; @@ -47,6 +48,7 @@ import org.eclipse.leshan.core.request.ReadRequest; import org.eclipse.leshan.core.response.ReadResponse; import org.eclipse.leshan.core.util.SecurityUtil; +import org.eclipse.leshan.core.util.datatype.ULong; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -94,6 +96,7 @@ public static ServersInfo getInfo(Map objectEnabler info.clientCertificate = getClientCertificate(security); info.serverCertificate = getServerCertificate(security); info.privateKey = getPrivateKey(security); + info.certificateUsage = getCertificateUsage(security); } infos.bootstrap = info; } @@ -115,6 +118,7 @@ public static ServersInfo getInfo(Map objectEnabler info.clientCertificate = getClientCertificate(security); info.serverCertificate = getServerCertificate(security); info.privateKey = getPrivateKey(security); + info.certificateUsage = getCertificateUsage(security); } // search corresponding device management server for (LwM2mObjectInstance server : servers.getInstances().values()) { @@ -208,6 +212,10 @@ public static SecurityMode getSecurityMode(LwM2mObjectInstance securityInstance) return SecurityMode.fromCode((long) securityInstance.getResource(SEC_SECURITY_MODE).getValue()); } + public static CertificateUsage getCertificateUsage(LwM2mObjectInstance securityInstance) { + return CertificateUsage.fromCode((ULong) securityInstance.getResource(SEC_CERTIFICATE_USAGE).getValue()); + } + public static String getPskIdentity(LwM2mObjectInstance securityInstance) { byte[] pubKey = (byte[]) securityInstance.getResource(SEC_PUBKEY_IDENTITY).getValue(); return new String(pubKey); diff --git a/leshan-integration-tests/credentials/clientKeyStore.jks b/leshan-integration-tests/credentials/clientKeyStore.jks index c93f252bef8e9867306f76be1f2dfe7e1694c114..d885ed157f33dbd45f9f8195b4df25f6b28f7f63 100644 GIT binary patch literal 3548 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 HBozG%%vHss literal 2791 zcmezO_TO6u1_mY|W(Cu1Mfv$9$%zaMjKzx!?UWfoYgC@pYAQo7_%*4pV z#9~zRNydPOjYF%=O4UZ-6D zRX1h2>fH15vSwMkhP&uU|6lEw;h249YWkv%nl&qgFX`5IoS6_!V9Yh= z2(P%L>G2s%YdSko1A*C-!N844k)fUO{kjvOJSXOh34byBQ?uK0XJ7l7f+dsnTPKJL ztvsj)RPtRZy) zWoKqWO;5}nNa;!a+*Ng%6LaUEx5zaLy2*Owo5!rfsG-N~!C>IZq>%P@UjA>*mPhW3 zrrw#iwnXvnn@ofDm%rKNH=Q+~ZuN0BFgb0uIHk8zyI0}B-n-%2i~flnW^Zur?2P8h zF_|b@Np;?LZRc{b#Vjw;% znWASU(wcpw1crnMsl1WZUnD=UzHIFYfg6{_MA~=Y{Je z&hy^>Yt8*L*m=LD8#5`?tIR0dd?3GF+KKBE)h)mn-2lYF&{$*ck22BJ>O${lvXsJ z`uqDXO7s?|=A^|JXQt=DqSw|15xod;}7}B!JSZQY49l4oZN~q=WRTp+!JC5mX=uQbLm^h=_>v-VB0t z5FQ;N6j4Nw5*{K|LKN|Pvs^gkv{(4Ec!48B7MlI9Dt1MXJYyD5i5v}K0gE*gp^78#sDZd*GW(}OacHp+XclG_oh6Cx2qo5ODgGE}}44MnLV zdH&TSGYkdcX9f5JZl9h&z)gS)Qs^%ej)F0qwea+I6-3D?DIk$@C|LzG3WbcE`yWvB z9Z-Mv<943R{-w+fm1{({ckxT;EI^z4+zKj3D2%O8>-sV@p4uX0ww4Rs}W9?QY99U?pzx<1iXiDi~5PgPj>t2PJq+hawyrC->B zE->+#Hy3q$4G>PYSN~5r1)Ku;1A_m4|CgMUE-NY_i6GH`jpqzgJ`n^zl{o0>0H+1? zmqYh&d&u1xM_r4D7nAH(f3+2IJfrV3r>?EGHq?v$3D;q#!JAv(xhuV^V!`S?Nfqv`dT zE{zub3&XWekwM@*tvKCeLqXi-R_$v!4>MHvA#L(2tWQgK_WB^;4{YRma!~I*7586B zzLbz{q5C&}Ap<#FNe`-GKY8CODg^uOwydgIOo(mYTueMn zRu};pmpJl-fQE4KGJRrKIES_i z$!fFc!MR<{fkxO3aIpeQD))mE%^Eoyw#t@oTZHwC-bSO}7$m0*Vt4Wk0hzu+auCxT3Z=~&vs#kzo+H7!6WMH;S z75nn7;H&3%wy2$JFZaG!`Dnob)>_`;A~c2yssvD_F;&@mi&Wkb<{_&3E&}OIK6J9jk+$gH-LgayK*b!#B~) z2lfQ-xqXMEIIlqdv1iQJes!8-&b9)qCP@t4icz)O%G8T&1epGaQQjXMp9)$01#8j- zM@*W(L(VYwbBTEwl*YP6zPpCOeS;%9;VRpF{YDj|gplWnv%XCgQyLF?&}d9tVGKw3 zB_T7*B1`>;QI)J=-AC`HM-hK3OR~dBuP%y!i>tdewj$LG9f>KC#)re<2gBKnc#JX-Nq~ zsy!B6tJ5|lK54%K`4IPp1;?7bZOau<%#H;nQqJ=3xKvA@*VIW{yKOKU@UBjug6r+(Tsl1;)S2YZVL zJGC`V{z}aX`;E0_%si*fUYKl#+3@+p8E?RIn9DtR|6UX6ipjf1%?WfCD&J=_lxH+x zI5Gq+I?>3F+xJfXu~Fs~<&@F@^z+H_}grB;&c4+Ed{f!y<_#SsS=n zibU$*)2`#GxukSSwlw**k-|CwDKbKBJj6WrMG!dNWn5$u>mP-rW(0p}&E=j~1P0Sp^O^x~|piB$KQbWRUYD7Tqby!oT*9*4KNd}TzGCR6m@ zx4qIXuAqZjH-QoxAu_H35WK+2E)iFBro`TZ5W47JV#+#RUF|gNL^sK(lGYtB;LV)z zV;Go^S@`8ZYN=w+v7pv17{qxIY%GS&Z_g&?$f$n~{x*7tmns?AH9FnOX|M-9;xg+n zJ@9|7_`AahMSC@7@sBz(!V}kBSg}W4K9pk~EA3x?l)_j4x;|A&5_!#H_#E%@Zf?uR zOP1Eh{N_!4gXKPqs@}?KY@tMeR-q?i^vL1<1>JP2p2J{-{MQ|iM7lZy@2;47<~y1? zLw8K@wX}3(`I7?MjGz0w{8x=XD5g(O~qZ74PL-<;;u^wiHU{o>I)rxnEkB-jNvU-oNutJ%qc$7KGnR*l|YHSyCD8}QQN#{8b7LFZ^fdbF3mfkaHz_x;ZI^~)l<3A8yTUxfSbChgR_!7SLz z9#V&&P3JA+dgbf`3=Ch%1^fAX`Ad1^6vS;ewxV<7<0?m3sBvU><^EXccwZf#Q7ou} zt75N7h0vXC&BFsWW5mpFc}z`HGn#v3fkVQ{Ob1y@0FH?tQ?;tmUho=(YVR9ZyL)Z9 z8nd>CKtR;Ik=YIr`2Qhy6Z-{jtj7L&+_w zZx*!q3AvXZH~uKfVsUj{xof}iu)7lalS@kEn-LcC*6EYYA6Lq+mEyOQ@qw&A?NKfo zF%uV0;B6Xo{a{UAKnQ*fvm563(ez~`E~)HT)zY?zeIo#>Vy20%+sn_k*w}P0_SM^L z&Tt!rBriO@( zu3K4&$6(sa-|5$nMBlQau6EhU3V)p2-u=9d^RRenXW8o&c=hLHO2Kd`T&0g)Adhw= zA$|-pf-ak0{;Xyn5fcAX5LZ;-*YEb=W7OIpN;;s5GH-XZg18;*PYA{qIS2-}har2oI5no%67lA-S=Cbc}iXQLzh=1~Lt6TUM z-5U0riP1UoGeGS<`UZ+t%+Pqy z`@0JMA_Vh=m=cyHH?^tj%~tRF7F{XRt-n6SkD!{Ot9%9fXU@Qt-xb2yaz#V8CpQlhMkT}eWGjTZ8hE8Ti16P;#0vFK~tZ>#i>!CvIPW;VuF z`dEuGj9(j6>>Bvfq|^^>xx8%&Q;;HV8p|SX)o0ck+)<7nD)T477jusliqHVKspq#Dc{;#yAt0lul zRt8+|;Fc;n37{y}h1(UT_rIP|=T=*kos<^T5>wr`#IU@Ea;rNQ(7hIUQi!~Q6hbmH zF-k#z^ye7?46x5Q%U6}Dno6kOU`IwY_d#%6x()+OZm9T@yC&$_6TgP4M+Oi%F1?k(GfZ z`_rla(~N#fM!lHvDeSC%qSCYZVpEU*E_``$@A7wwQ~PR19M|T15;BoL!&4Oej`JW01!e1 z@M(@T5N2Zs+rz{NwUC*So!N-vw+$e8_1Io|EG4d?_W26(bq z08A2dfY=_IENXuJP(=+9d@+lfER4~Ug>jUDgrS&$2qaDMLemr^L=14J3huxpwV>;J z#4NHKE?w^aQla}|!JEWQmfaJlX4uFlE>&B-v?0v;fdpHih_C(T6@Pz(-gu;Etf2n> z_)=9~y;D=_7Z({67|4SnU71C~K&%0Kv~z+K2(vI5FaVP$kg3YTW5C760nDzftnAE; zsHup#11S~VlK8oO=47=nzs_IfyJr}N{!yr1hZ<(ERJ7|+w(2?+`;O*0{J*B|Ry$n# zkjv?HH`|dNnOdKj+f+db?QB&aUwN|o%Vo>klKx37NfNoF#Um*s(DC`sXR!rAFK;5E zYBUEANDk&N%_}J?EiOq-K`!Af&fv<*x15Y$x|eRyddmK6{ikY0?-j{+Bv)?dSNkLS zcCQ}e%?V2Oj~73?xx;nW#NuDE<}!P=Kgm~3R9<#C_Stel??fi^TlY4k6wS?xWX*WH z`ouQYcW0|rF8h_JzJA55;_$(Fde4lNUw7wPUG!ja5d)Vn@T}Yl%*KsCtOCu-Nf**R zQIn;CvY{e4V*pEd321JF`wmB0k1bOZWeo28{p3xW!L#;uu`IpnDRKqw53Qfp{#o&` z^lRhW^ZJYSnfU&iYap`x#g8|>Ph*7HZ+@#~ZMFE?x@+D6H{rQk1-su*A+^*$7I4Wt zk#WVL;@NyXyibpNq`2Mth#D}k{Q5Wc)Uu?x-L(~4zvbQt&YAUHX7i)MJs-K36#vt| z(*FJiFuxwxpR2l|NO=i=K$O!YFW>v8wHrRUf9N|>{6@v;VfK^7;Nn#XQpUv>r{<)^ z7iXsDrKUh?0IMQIex3%5t4Tm?3XQL5X?53Y(o+FsvM$7Aw8|M< zgb`;B?ii!EL=H6YH=sv>`z(IZrt{PFW|ii0<+E6Q{>~TeSbVMj)YK)rZ@*A&$u9;* z;DiUW?#(G&TKeahq38NJ2d;7bF7`6Jy~B510@vrRLHo?>r3bI=- JuHDD@9{{(aIjjHx From 3e65c99840f85a1a81f583fe9e85afbd859bed4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vesa=20J=C3=A4=C3=A4skel=C3=A4inen?= Date: Sun, 27 Sep 2020 12:16:11 +0300 Subject: [PATCH 3/4] leshan-integration-tests: credentials: Update with intermediate and add manufacturer CA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split own key stores for different CA's. Add intermediate CA for making chain validation tests. Add manufacturer CA for making client certificates with that. Signed-off-by: Vesa Jääskeläinen Also-by: Simon Bernard --- .../credentials/clientKeyStore.jks | Bin 3548 -> 4844 bytes .../credentials/generate_credentials.sh | 140 ++++++++++++++++-- .../credentials/manufacturerCaKeyStore.jks | Bin 0 -> 1676 bytes .../credentials/serverKeyStore.jks | Bin 3352 -> 3805 bytes .../credentials/trustedCaKeyStore.jks | Bin 0 -> 1531 bytes .../credentials/unknownCaKeyStore.jks | Bin 0 -> 595 bytes 6 files changed, 128 insertions(+), 12 deletions(-) create mode 100644 leshan-integration-tests/credentials/manufacturerCaKeyStore.jks create mode 100644 leshan-integration-tests/credentials/trustedCaKeyStore.jks create mode 100644 leshan-integration-tests/credentials/unknownCaKeyStore.jks diff --git a/leshan-integration-tests/credentials/clientKeyStore.jks b/leshan-integration-tests/credentials/clientKeyStore.jks index d885ed157f33dbd45f9f8195b4df25f6b28f7f63..46430a78c009ede25157ace0f2613fad90dd75a6 100644 GIT binary patch literal 4844 zcmeH~c~p~E8pg8+kR>6kDmCnutv4YHPyxk?-~s}HA}#?#fM`rG2~f}qG76{_SwvbC zf`GCW1gr~c1yS6PWfXD1q9Ta9qJlD3VJ;z#CLWX%XgF9?|%39Jnwto zkw+ts5C{YchKlTp6A6V9P6z^ljJo;H2jK{8pdB4J!rMrYh~&c{;Aw?hP;?VvWG)Z#-R~!){Adk&Po;?eY^);w~LZLWPXf!6xF~~rR zN`V7_%8(Cy?9Yn<35S(C+kyM(yhwQtVR=$Gv^XD zyGpul?9b9Vgnhbfm6~36o#@h*+{`JM{&op#$E_4Gkfe~D?ktRkD zqm$q3GiO;oTX)Hwon@}`SgBRb%iDnF*w57p76geQ@s-N&c&D(GBuFh7J z6fc}#GGxx(c`j@Xe`DX_^ihZdiNJCAJgz`8j^nWd9E%6v!X>F$k54L{>iFV+g;n2{oJfK^HN4Yy>r>x%u$hf_?4UyPRy;y(pSaLX4IJC zlN;A+_T(^qX2-^KejzQ4HNM>WY!QA_Po*#z`GlA`#V%Pr1vIje2LDsul@o1Fd?v2Zd?5fH+ z*u1Vsm$m;?08VGgc8dy<_IXd8wz^@fg(?0O#!ztI>*Bq|rmWE}>=n`0=bm<7_O=+k z_#%A%RI`iBkr~@J{^evvRR3EiqYxV7PG+wN31xExKxs zE&M(wnNdstdE7~cawo}G6vLB5$d~nh;3Z?k15*umi{52}9S-%3rsZB&8p$b#yV_?+ zGIU6{8{1aSMUhRGwiJAe%Pc0=6c|pjPH2lYKNhoK*SS1ze_rUKlJ#d~sabV(Sor(d zdDv>A?Ch2Ec|aM%YqDir;L#LXaCvIW=5j~>REIZ5r_i4E3cDR=HZI0XbB<8JtR%Ko z>EH!3{nA!?gqVLdj(w)W>43q$pxA4{A?N#uyOT1ti*H8|8g>RF$DVKtO<)m!q6y=L`?Sm(7}yPQ7+MxAn@B1G;y&`)HKn%ZxgM5 zk2j6<>xfeyd0-^2xgWLfYV~m0T`ZX+%{qL?ti;6Y746Y({LS`_OQ@cK4#8xutaDT(RpR$Q2)dN(PD z-@NBw@~Ba*^GY${t{a1JSLaQR%)06@sX%Xx`R(l?eCX_7kpEnei4bz6+-UE&TZ8@Y zNEbjW=fQB3+c~%|pP{Hc@cZoyl8MJF2-Thw2md*h@>&1I}v~*<_sYwnf_3qqlq)ZF|Y0_WOTOU#~FK^nJtVRBF&Z=tpH! ze_DffeinXcX1BqKuKtK`fJY3re_P$vb?7IC6%V-`**<1JqR4tx8fUK)+EG4y>dpNQ z+}7|*#c`W=7%k0RD=nZLI=)b{p zDV5a|0o-BTyw0gE^s9Dxvhwaz@5<>L7x{+_X}jGL?U;Hl<>HCB>3;Ah)xIV9Z;qTY z_3qH?tnzE$IgpnBL))CR4pY`~s-JlE4+?n2Tz(i^%nKL1#e09lJG>bXZ7K|k9Pe^> zWV#aGPw8V7yJ5OAUHTtR*9UmNS73i@H~b0Bt{mR*V{Ds-^xCHTH<0dD?yE(&^a)L^ zZ&>{{&#o5TBzWwF@Lshiujg%@)=w*J3W~o(@9g%8Kj!jq((SHmY@^ra26fSd8x^ZS Tc2Yt@P4UoagW8PJDad~T@`DBT literal 3548 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 HBozG%%vHss diff --git a/leshan-integration-tests/credentials/generate_credentials.sh b/leshan-integration-tests/credentials/generate_credentials.sh index caf1212d3f..5fec982aa8 100755 --- a/leshan-integration-tests/credentials/generate_credentials.sh +++ b/leshan-integration-tests/credentials/generate_credentials.sh @@ -1,12 +1,20 @@ #!/bin/bash # Keystore parameters + CLIENT_STORE=clientKeyStore.jks CLIENT_STORE_PWD=client SERVER_STORE=serverKeyStore.jks SERVER_STORE_PWD=server +TRUSTED_CA_STORE=trustedCaKeyStore.jks +TRUSTED_CA_STORE_PWD=trusted +MANUFACTURER_CA_STORE=manufacturerCaKeyStore.jks +MANUFACTURER_CA_STORE_PWD=manufacturer +UNKNOWN_CA_STORE=unknownCaKeyStore.jks +UNKNOWN_CA_STORE_PWD=unknown VALIDITY=36500 #days +DEFAULT_STORE_TYPE=JKS #PKCS12 is not supported by Java7 # Color output stuff red=`tput setaf 1` @@ -17,26 +25,83 @@ H1=${green}${bold} H2=${blue} RESET=`tput sgr0` -# Generation of the keystore needed for Leshan integration tests. -echo "${H1}Server Keystore : ${RESET}" -echo "${H1}==================${RESET}" +# Generation of the Trusted CA keystore needed for Leshan integration tests. +echo "${H1}Trusted CA Keystore : ${RESET}" +echo "${H1}======================${RESET}" echo "${H2}Creating the trusted root CA key and certificate...${RESET}" keytool -genkeypair -alias rootCA -keyalg EC -dname 'CN=Leshan root CA' \ -validity $VALIDITY \ + -storetype $DEFAULT_STORE_TYPE \ -ext BasicConstraints:critical=ca:true \ -ext KeyUsage:critical=keyCertSign,cRLSign \ - -keypass $SERVER_STORE_PWD -keystore $SERVER_STORE -storepass $SERVER_STORE_PWD + -keypass $TRUSTED_CA_STORE_PWD -keystore $TRUSTED_CA_STORE -storepass $TRUSTED_CA_STORE_PWD +keytool -exportcert -alias rootCA -keystore $TRUSTED_CA_STORE -storepass $TRUSTED_CA_STORE_PWD -file rootCA.der +echo +echo "${H2}Creating the intermediate CA key and certificate...${RESET}" +keytool -genkeypair -alias intermediateCA -keyalg EC -dname 'CN=Leshan intermediate CA' \ + -validity $VALIDITY \ + -storetype $DEFAULT_STORE_TYPE \ + -ext BasicConstraints:critical=ca:true,pathlen:0 \ + -ext KeyUsage:critical=keyCertSign,cRLSign \ + -keypass $TRUSTED_CA_STORE_PWD -keystore $TRUSTED_CA_STORE -storepass $TRUSTED_CA_STORE_PWD +echo +keytool -certreq -alias intermediateCA -dname 'CN=Leshan intermediate CA' -keystore $TRUSTED_CA_STORE -storepass $TRUSTED_CA_STORE_PWD | \ + keytool -gencert -alias rootCA -keystore $TRUSTED_CA_STORE -storepass $TRUSTED_CA_STORE_PWD \ + -validity $VALIDITY \ + -ext BasicConstraints:critical=ca:true,pathlen:0 \ + -ext KeyUsage:critical=keyCertSign,cRLSign | \ + keytool -importcert -alias intermediateCA -keystore $TRUSTED_CA_STORE -storepass $TRUSTED_CA_STORE_PWD +keytool -exportcert -alias intermediateCA -keystore $TRUSTED_CA_STORE -storepass $TRUSTED_CA_STORE_PWD -file intermediateCA.der +echo + +# Generation of the Manufacturer CA keystore needed for Leshan integration tests. +echo "${H1}Manufacturer CA Keystore : ${RESET}" +echo "${H1}======================${RESET}" +echo "${H2}Creating the trusted root CA key and certificate...${RESET}" +keytool -genkeypair -alias mfgProductsRootCA -keyalg EC -dname 'CN=Products Root CA,O=Manufacturer' \ + -validity $VALIDITY \ + -storetype $DEFAULT_STORE_TYPE \ + -ext BasicConstraints:critical=ca:true \ + -ext KeyUsage:critical=keyCertSign,cRLSign \ + -keypass $MANUFACTURER_CA_STORE_PWD -keystore $MANUFACTURER_CA_STORE -storepass $MANUFACTURER_CA_STORE_PWD +keytool -exportcert -alias mfgProductsRootCA -keystore $MANUFACTURER_CA_STORE -storepass $MANUFACTURER_CA_STORE_PWD -file mfgProductsRootCA.der echo +echo "${H2}Creating the Devices CA key and certificate...${RESET}" +keytool -genkeypair -alias mfgDevicesCA -keyalg EC -dname 'CN=Devices CA,O=Manufacturer' \ + -validity $VALIDITY \ + -storetype $DEFAULT_STORE_TYPE \ + -ext BasicConstraints:critical=ca:true,pathlen:0 \ + -ext KeyUsage:critical=keyCertSign,cRLSign \ + -keypass $MANUFACTURER_CA_STORE_PWD -keystore $MANUFACTURER_CA_STORE -storepass $MANUFACTURER_CA_STORE_PWD +echo +keytool -certreq -alias mfgDevicesCA -dname 'CN=Devices CA,O=Manufacturer' -keystore $MANUFACTURER_CA_STORE -storepass $MANUFACTURER_CA_STORE_PWD | \ + keytool -gencert -alias mfgProductsRootCA -keystore $MANUFACTURER_CA_STORE -storepass $MANUFACTURER_CA_STORE_PWD \ + -validity $VALIDITY \ + -ext BasicConstraints:critical=ca:true,pathlen:0 \ + -ext KeyUsage:critical=keyCertSign,cRLSign | \ + keytool -importcert -alias mfgDevicesCA -keystore $MANUFACTURER_CA_STORE -storepass $MANUFACTURER_CA_STORE_PWD +keytool -exportcert -alias mfgDevicesCA -keystore $MANUFACTURER_CA_STORE -storepass $MANUFACTURER_CA_STORE_PWD -file mfgDevicesCA.der +echo + +# Generation of the Unknown CA keystore needed for Leshan integration tests. +echo "${H1}Unknown CA Keystore : ${RESET}" +echo "${H1}======================${RESET}" echo "${H2}Creating an untrusted root CA key and certificate...${RESET}" -keytool -genkeypair -alias untrustedrootCA -keyalg EC -dname 'CN=Leshan untrusted root CA' \ +keytool -genkeypair -alias untrustedRootCA -keyalg EC -dname 'CN=Leshan untrusted root CA' \ -validity $VALIDITY \ + -storetype $DEFAULT_STORE_TYPE \ -ext BasicConstraints:critical=ca:true \ -ext KeyUsage:critical=keyCertSign,cRLSign \ - -keypass $SERVER_STORE_PWD -keystore $SERVER_STORE -storepass $SERVER_STORE_PWD + -keypass $UNKNOWN_CA_STORE_PWD -keystore $UNKNOWN_CA_STORE -storepass $UNKNOWN_CA_STORE_PWD +keytool -exportcert -alias untrustedRootCA -keystore $UNKNOWN_CA_STORE -storepass $UNKNOWN_CA_STORE_PWD -file untrustedRootCA.der echo +# Generation of the keystore needed for Leshan integration tests. +echo "${H1}Server Keystore : ${RESET}" +echo "${H1}==================${RESET}" echo "${H2}Creating server key and self-signed certificate ...${RESET}" keytool -genkeypair -alias server -keyalg EC -dname 'CN=localhost' \ -validity $VALIDITY \ + -storetype $DEFAULT_STORE_TYPE \ -ext BasicConstraints=ca:false \ -ext KeyUsage:critical=digitalSignature,keyAgreement \ -ext ExtendedkeyUsage=serverAuth \ @@ -44,15 +109,42 @@ keytool -genkeypair -alias server -keyalg EC -dname 'CN=localhost' \ keytool -exportcert -alias server -keystore $SERVER_STORE -storepass $SERVER_STORE_PWD | \ keytool -importcert -alias server_self_signed -keystore $SERVER_STORE -storepass $SERVER_STORE_PWD -noprompt +echo +echo "${H2}Creating second server key and self-signed certificate ...${RESET}" +keytool -genkeypair -alias serverInt -keyalg EC -dname 'CN=Server signed with Intermediate CA' -ext san=dns:localhost \ + -validity $VALIDITY \ + -storetype $DEFAULT_STORE_TYPE \ + -ext BasicConstraints=ca:false \ + -ext KeyUsage:critical=digitalSignature,keyAgreement \ + -ext ExtendedkeyUsage=serverAuth \ + -keypass $SERVER_STORE_PWD -keystore $SERVER_STORE -storepass $SERVER_STORE_PWD +keytool -exportcert -alias serverInt -keystore $SERVER_STORE -storepass $SERVER_STORE_PWD | \ + keytool -importcert -alias serverInt_self_signed -keystore $SERVER_STORE -storepass $SERVER_STORE_PWD -noprompt +echo +echo "${H2}Importing Root CA certificate ...${RESET}" +keytool -importcert -alias rootCA -keystore $SERVER_STORE -storepass $SERVER_STORE_PWD -noprompt -file rootCA.der +echo +echo "${H2}Importing Intermediate CA certificate ...${RESET}" +keytool -importcert -alias intermediateCA -keystore $SERVER_STORE -storepass $SERVER_STORE_PWD -noprompt -file intermediateCA.der echo echo "${H2}Creating server certificate signed by root CA...${RESET}" keytool -certreq -alias server -dname 'CN=localhost' -keystore $SERVER_STORE -storepass $SERVER_STORE_PWD | \ - keytool -gencert -alias rootCA -keystore $SERVER_STORE -storepass $SERVER_STORE_PWD \ + keytool -gencert -alias rootCA -keystore $TRUSTED_CA_STORE -storepass $TRUSTED_CA_STORE_PWD \ -validity $VALIDITY \ -ext BasicConstraints=ca:false \ -ext KeyUsage:critical=digitalSignature,keyAgreement \ -ext ExtendedkeyUsage=serverAuth | \ keytool -importcert -alias server -keystore $SERVER_STORE -storepass $SERVER_STORE_PWD +echo +echo "${H2}Creating server certificate signed by intermediate CA...${RESET}" +keytool -certreq -alias serverInt -dname 'CN=Server signed with Intermediate CA' -ext san=dns:localhost -keystore $SERVER_STORE -storepass $SERVER_STORE_PWD | \ + keytool -gencert -alias intermediateCA -keystore $TRUSTED_CA_STORE -storepass $TRUSTED_CA_STORE_PWD \ + -validity $VALIDITY \ + -ext BasicConstraints=ca:false \ + -ext KeyUsage:critical=digitalSignature,keyAgreement \ + -ext ExtendedkeyUsage=serverAuth \ + -ext san=dns:localhost | \ + keytool -importcert -alias serverInt -keystore $SERVER_STORE -storepass $SERVER_STORE_PWD echo echo "${H1}Client Keystore : ${RESET}" @@ -60,6 +152,7 @@ echo "${H1}==================${RESET}" echo "${H2}Creating client key and self-signed certificate with expected CN...${RESET}" keytool -genkeypair -alias client -keyalg EC -dname 'CN=leshan_integration_test' \ -validity $VALIDITY \ + -storetype $DEFAULT_STORE_TYPE \ -ext BasicConstraints=ca:false \ -ext KeyUsage:critical=digitalSignature,keyAgreement \ -ext ExtendedkeyUsage=clientAuth \ @@ -68,12 +161,11 @@ keytool -exportcert -alias client -keystore $CLIENT_STORE -storepass $CLIENT_STO keytool -importcert -alias client_self_signed -keystore $CLIENT_STORE -storepass $CLIENT_STORE_PWD -noprompt echo echo "${H2}Import root certificate just to be able to sign certificate ...${RESET}" -keytool -exportcert -alias rootCA -keystore $SERVER_STORE -storepass $SERVER_STORE_PWD | \ - keytool -importcert -alias rootCA -keystore $CLIENT_STORE -storepass $CLIENT_STORE_PWD -noprompt +keytool -importcert -alias rootCA -keystore $CLIENT_STORE -storepass $CLIENT_STORE_PWD -noprompt -file rootCA.der echo echo "${H2}Creating client certificate signed by root CA with expected CN...${RESET}" keytool -certreq -alias client -keystore $CLIENT_STORE -storepass $CLIENT_STORE_PWD | \ - keytool -gencert -alias rootCA -keystore $SERVER_STORE -storepass $SERVER_STORE_PWD \ + keytool -gencert -alias rootCA -keystore $TRUSTED_CA_STORE -storepass $TRUSTED_CA_STORE_PWD \ -validity $VALIDITY \ -ext BasicConstraints=ca:false \ -ext KeyUsage:critical=digitalSignature,keyAgreement \ @@ -82,7 +174,7 @@ keytool -certreq -alias client -keystore $CLIENT_STORE -storepass $CLIENT_STORE_ echo echo "${H2}Creating client certificate signed by root CA with bad/unexpected CN...${RESET}" keytool -certreq -alias client -dname 'CN=leshan_client_with_bad_cn' -keystore $CLIENT_STORE -storepass $CLIENT_STORE_PWD | \ - keytool -gencert -alias rootCA -keystore $SERVER_STORE -storepass $SERVER_STORE_PWD \ + keytool -gencert -alias rootCA -keystore $TRUSTED_CA_STORE -storepass $TRUSTED_CA_STORE_PWD \ -validity $VALIDITY \ -ext BasicConstraints=ca:false \ -ext KeyUsage:critical=digitalSignature,keyAgreement \ @@ -91,9 +183,33 @@ keytool -certreq -alias client -dname 'CN=leshan_client_with_bad_cn' -keystore $ echo echo "${H2}Creating client certificate signed by untrusted root CA with expected CN...${RESET}" keytool -certreq -alias client -keystore $CLIENT_STORE -storepass $CLIENT_STORE_PWD | \ - keytool -gencert -alias untrustedrootCA -keystore $SERVER_STORE -storepass $SERVER_STORE_PWD \ + keytool -gencert -alias untrustedRootCA -keystore $UNKNOWN_CA_STORE -storepass $UNKNOWN_CA_STORE_PWD \ -validity $VALIDITY \ -ext BasicConstraints=ca:false \ -ext KeyUsage:critical=digitalSignature,keyAgreement \ -ext ExtendedkeyUsage=clientAuth | \ keytool -importcert -alias client_not_trusted -keystore $CLIENT_STORE -storepass $CLIENT_STORE_PWD -noprompt +echo +echo "${H2}Creating mfg client key and self-signed certificate with expected CN...${RESET}" +keytool -genkeypair -alias mfgClient -keyalg EC -dname 'CN=urn:dev:ops:32473-IoT_Device-K1234567,O=Manufacturer' \ + -validity $VALIDITY \ + -storetype $DEFAULT_STORE_TYPE \ + -ext BasicConstraints=ca:false \ + -ext KeyUsage:critical=digitalSignature,keyAgreement \ + -ext ExtendedkeyUsage=clientAuth \ + -keypass $CLIENT_STORE_PWD -keystore $CLIENT_STORE -storepass $CLIENT_STORE_PWD +echo +echo "${H2}Import mfg products root CA certificate just to be able to sign certificate ...${RESET}" +keytool -importcert -alias mfgProductsRootCA -keystore $CLIENT_STORE -storepass $CLIENT_STORE_PWD -noprompt -file mfgProductsRootCA.der +echo +echo "${H2}Import mfg devices CA certificate just to be able to sign certificate ...${RESET}" +keytool -importcert -alias mfgDevicesCA -keystore $CLIENT_STORE -storepass $CLIENT_STORE_PWD -noprompt -file mfgDevicesCA.der +echo +echo "${H2}Creating mfg client certificate signed by root CA with expected CN...${RESET}" +keytool -certreq -alias mfgClient -keystore $CLIENT_STORE -storepass $CLIENT_STORE_PWD | \ + keytool -gencert -alias mfgDevicesCA -keystore $MANUFACTURER_CA_STORE -storepass $MANUFACTURER_CA_STORE_PWD \ + -validity $VALIDITY \ + -ext BasicConstraints=ca:false \ + -ext KeyUsage:critical=digitalSignature,keyAgreement \ + -ext ExtendedkeyUsage=clientAuth | \ + keytool -importcert -alias mfgClient -keystore $CLIENT_STORE -storepass $CLIENT_STORE_PWD -noprompt diff --git a/leshan-integration-tests/credentials/manufacturerCaKeyStore.jks b/leshan-integration-tests/credentials/manufacturerCaKeyStore.jks new file mode 100644 index 0000000000000000000000000000000000000000..007b04e4cb7d42034a73dbe65fee8b7c176aa4b4 GIT binary patch literal 1676 zcmezO_TO6u1_mZ5W@O;WO-oNnEz3+!Ely5kU|=kL@bhLgP`2Kn)_{+VOPh_6g;9%1 zkdcvTHPbp0nJR1`2r-q*1rmB7^CE#R zUIJJp^8BgW zpR24;^801-b`E=tbGgULkg$+-W)_o*j>s*v+K|3D%^<}<7HFd^ABz}^$ZF#yIp-o; z*7ooC{N{^P>7nI82j>H$3n+Yv>H*P!7u+Vt^iiu$-g_h_{I_9s-sC$69tEWu&lG@H0H;n!yN%95#HM_ak$-n_A zLb1jLdW7=BBb3#E85p6c!3K-0laB0P9qvl(yY(!i!oZ`P^;z%!>ov^pCD*=5y*52i zWet;p*aqI?_XMsm1?Ct%SZ|SfKK;`2s?I60F>|ZuFEZS=Ck~kR7#ReC1w#Qe!xRDY z3#@dwvJzM6&}{qrl;H-gBhqzg*N)69yrUCdu(s?#p`#+__sP1a@0s#ySymS|eoepl z@%o08+-}X>_I;aXMJ<<%PpEUOjj^5hVTnR)@{_|X{-?Ip-6?c9;k4>6g_RPBUOZ~;LW^sXeid+ENtSCMJ literal 0 HcmV?d00001 diff --git a/leshan-integration-tests/credentials/serverKeyStore.jks b/leshan-integration-tests/credentials/serverKeyStore.jks index cab5387fff5946c00b09011c638a32c1defc235c..c9095c43b842f9492f0fdd366fca560d1d172673 100644 GIT binary patch literal 3805 zcmeH~do+}39LL|=j3_h2kVG$qnCO{_hSX-WZc!>-&_#?PH4NicnpNaPMHDI2$uXr+ z87ke_;!xREx0OoCx};b_rA00KVv3PE_UxYB{^*b2dC&WtdFFZM_x*mp&oezOJuMIf zAw-e;pA;{j01n@q1ez+t;W5FGehS8Xmtax^dkCdBI@5Dp(CYECMOzzBi`hpe6f z#*xS9?XbQz7ef&e1XLKxfJR1_W2gefj^n@H)d%PEcmcTi_W)OxWda6+VZtypWElbH z2~;M77y!&!;sKz+m<-egCM$_258YDVmpB0hvQ+5Oyh{^QE*XS|qxh zUG1{Dx%6S9KsGZ+;5q+^FHNgeGw@`E7KjjaJNVJf)T~X*GjuwWxEH;%RYKUF(Ho0i zH3~g|d;jWc6if+IJjJ+}9nW{)=X`I!`ZKfBMk`X*JpdG9b81u=?!|~-3zNb4zITPb z_c4G>JP;THll#V|U=x7SHpSGsB^GN^U1+PGCuYuDuxyX0Z0#M%hN0FFus}4Rw>}l* zE2=#2qgBsB9;Gi*uCnN&{e)D{T;D8PXguK|ir}tOD;A~Rx z*GD(hEuHL@8$7jNLULcTKS)Gn%yt)Wr3_UdI`^G4N zATOP@vhdhkrIO1z!uh~#h-4#nd$?rOkCKr9N=PQzgb#9D2`{*-)5$E{L+vEh6x$xJ zw%i@(sB(LUecid`8E!po2)-g!uR-p28G8q(lt;IbBT_uu6CGNd#2X%d+=%+~dwU5v zU`X1Z!w=%{2@?;%^!zB{#uWn#Aa@zV_lD~SzNyRtHYDsmiYj3hWlmu)>mbs_|5A}fNg@x=Ebo_B{t?!u= za(02+EVSB6v`F!7P1LmH;^+Qe!tD>sQ<7~NDysFqXxeqvQ#1OF@{#Fs!W4Ii3J@D( zL9|7%WKTwer6k)%!wh0%DgOcsm{ zm*(==uH5xJ{{SG}Zzc=@lGu-!9SVJ))xyRB8S)rHdlE?sg(Vw3U_N}xuRg)~?O|3L zo8Dnnw>&E67C8u6=bj{*Shq&DHSWwL(xTZn+Q(TGbLe{3(WPS;Q7bY+yYh8WQiVZ5 z&dmw7g~fy1e~awCwtvl$P5YP;F8&;@hsyvJ19?${4k}qdKzfm=HDXYgryhuq^v~aA zOcL6e!=at|H9_kMIR84bqa{)Us)7yJH$Pat&1vJ24x32rps|dHwwde{nhfh|yh*!&wLjozozmDedu2zJ zj-JA|k@2}#^JWMQcxMdL_!@J~Z1?WkT~IQW>&tG+lYgrmUXN><)>SmnlOLZqMen&u zo&_m{y$%p%Dz=!}c&El;78~{b&TzP$44r`@V?2-}cqGn%AtCzt`+-7vL5oyEtH`PS z{Zbs4quV8Eo|`V9^*C=R)Gd~3v#biLpospxd?7>T&Ffcmdxv(7~W!9wrjsz&}BA$vFXZ%S}GNLSF>O+ z2)&krjAG_+c9{PIJ4=B5 zKVWC{XcTYh-NLl2*L>GyeY1LN(%Dq=Y2W1uw@_bdizwbYYfdBhLJHJCyFbgON4G}9 t$MME?JGzbOnKzC2(~wLDiq+E~+d~VXG)t2+G4G;{mKRRyoVToZ+FuLwuhRek literal 3352 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 literal 0 HcmV?d00001 diff --git a/leshan-integration-tests/credentials/unknownCaKeyStore.jks b/leshan-integration-tests/credentials/unknownCaKeyStore.jks new file mode 100644 index 0000000000000000000000000000000000000000..8c5295e4842db6193db60f424a394773ffe5085a GIT binary patch literal 595 zcmezO_TO6u1_mY|W&~sY(!7$Q(&CcTl%o9nlH^37cX_7 zT1I#^*?78N*l>6>Ncw-vdn83ceDi0cx=>dqRehsDl8swnn(Lg-0utaS<+Qn_iO$gy?G<6YU9xp z+WtTLIL~}e+u-`KMxV*i!Kv!j86IIod`p`oFrp^1sP zsZo>!zmXwOz`)21DnOhukp{wS>|nc@7@>|}W@Kk}Vqhsz3tV+$(=V%@KU<0yHXNOw z+V#(IYSsVOe?2P-;uG9%aqkE_8}W4W6@gXuD~|t6oOAZ;wuw(u0@v*Q`!Z+h{iLUh zoeUfdWP#q0qI9?cr5&`85k&6bF=(ilmL?= z!~R3(KDnN2|02h Date: Sun, 27 Sep 2020 14:03:06 +0300 Subject: [PATCH 4/4] SecurityTest: Add certificate usage unit tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Vesa Jääskeläinen Also-by : Simon Bernard --- .../leshan/client/californium/X509Util.java | 20 + .../tests/SecureIntegrationTestHelper.java | 71 +- .../integration/tests/SecurityTest.java | 892 ++++++++++++++++++ 3 files changed, 981 insertions(+), 2 deletions(-) diff --git a/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/X509Util.java b/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/X509Util.java index 7c207dc68a..afe6663676 100644 --- a/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/X509Util.java +++ b/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/X509Util.java @@ -19,11 +19,14 @@ import java.security.cert.CertPath; import java.security.cert.CertPathValidator; import java.security.cert.CertPathValidatorResult; +import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; import java.security.cert.PKIXCertPathValidatorResult; import java.security.cert.PKIXParameters; import java.security.cert.TrustAnchor; import java.security.cert.X509Certificate; +import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -122,4 +125,21 @@ public static boolean contains(X509Certificate certificate, X509Certificate[] ce } return false; } + + /** + * Convert array of {@link Certificate} to array of {@link X509Certificate} + */ + public static X509Certificate[] asX509Certificates(Certificate[] certificates) throws CertificateException { + ArrayList x509Certificates = new ArrayList<>(); + + for (Certificate cert : certificates) { + if (!(cert instanceof X509Certificate)) { + throw new CertificateException(String.format( + "%s certificate format is not supported, Only X.509 certificate is supported", cert.getType())); + } + x509Certificates.add((X509Certificate) cert); + } + + return x509Certificates.toArray(new X509Certificate[0]); + } } diff --git a/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/SecureIntegrationTestHelper.java b/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/SecureIntegrationTestHelper.java index 34537b7295..296f639b83 100644 --- a/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/SecureIntegrationTestHelper.java +++ b/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/SecureIntegrationTestHelper.java @@ -37,6 +37,8 @@ import java.security.spec.ECPrivateKeySpec; import java.security.spec.ECPublicKeySpec; import java.security.spec.KeySpec; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import javax.crypto.SecretKey; @@ -53,6 +55,7 @@ import org.eclipse.californium.scandium.dtls.cipher.CipherSuite; import org.eclipse.californium.scandium.dtls.pskstore.AdvancedPskStore; import org.eclipse.leshan.client.californium.LeshanClientBuilder; +import org.eclipse.leshan.client.californium.X509Util; import org.eclipse.leshan.client.engine.DefaultRegistrationEngineFactory; import org.eclipse.leshan.client.object.Device; import org.eclipse.leshan.client.object.Security; @@ -60,6 +63,7 @@ import org.eclipse.leshan.client.resource.DummyInstanceEnabler; import org.eclipse.leshan.client.resource.LwM2mObjectEnabler; import org.eclipse.leshan.client.resource.ObjectsInitializer; +import org.eclipse.leshan.core.CertificateUsage; import org.eclipse.leshan.core.LwM2mId; import org.eclipse.leshan.core.californium.EndpointFactory; import org.eclipse.leshan.core.util.Hex; @@ -89,8 +93,12 @@ public class SecureIntegrationTestHelper extends IntegrationTestHelper { // client private key used for X509 public final PrivateKey clientPrivateKeyFromCert; + // mfg client private key used for X509 + public final PrivateKey mfgClientPrivateKeyFromCert; // server private key used for X509 public final PrivateKey serverPrivateKeyFromCert; + // server private key used for X509 + public final PrivateKey serverIntPrivateKeyFromCert; // client certificate signed by rootCA with a good CN (CN start by leshan_integration_test) public final X509Certificate clientX509Cert; // client certificate signed by rootCA but with bad CN (CN does not start by leshan_integration_test) @@ -99,14 +107,25 @@ public class SecureIntegrationTestHelper extends IntegrationTestHelper { public final X509Certificate clientX509CertSelfSigned; // client certificate signed by another CA (not rootCA) with a good CN (CN start by leshan_integration_test) public final X509Certificate clientX509CertNotTrusted; + // client certificate signed by manufacturer CA's with a good CN + // (CN=urn:dev:ops:32473-IoT_Device-K1234567,O=Manufacturer) + public final X509Certificate[] mfgClientX509CertChain; // server certificate signed by rootCA public final X509Certificate serverX509Cert; + // server certificate signed by intermediateCA + public final X509Certificate[] serverIntX509CertChain; // self-signed server certificate public final X509Certificate serverX509CertSelfSigned; + // self-signed server certificate + public final X509Certificate serverIntX509CertSelfSigned; // rootCA used by the server public final X509Certificate rootCAX509Cert; // certificates trustedby the server (should contain rootCA) public final Certificate[] trustedCertificates = new Certificate[1]; + // client's initial trust store + public final List clientTrustStore; + // client's initial empty trust store + public final List clientEmptyTrustStore = new ArrayList<>(); public SecureIntegrationTestHelper() { // create client credentials @@ -145,6 +164,9 @@ public SecureIntegrationTestHelper() { clientX509CertWithBadCN = (X509Certificate) clientKeyStore.getCertificate("client_bad_cn"); clientX509CertSelfSigned = (X509Certificate) clientKeyStore.getCertificate("client_self_signed"); clientX509CertNotTrusted = (X509Certificate) clientKeyStore.getCertificate("client_not_trusted"); + + mfgClientPrivateKeyFromCert = (PrivateKey) clientKeyStore.getKey("mfgClient", clientKeyStorePwd); + mfgClientX509CertChain = X509Util.asX509Certificates(clientKeyStore.getCertificateChain("mfgClient")); } catch (GeneralSecurityException | IOException e) { throw new RuntimeException(e); } @@ -181,11 +203,14 @@ public SecureIntegrationTestHelper() { } serverPrivateKeyFromCert = (PrivateKey) serverKeyStore.getKey("server", serverKeyStorePwd); + serverIntPrivateKeyFromCert = (PrivateKey) serverKeyStore.getKey("serverint", serverKeyStorePwd); rootCAX509Cert = (X509Certificate) serverKeyStore.getCertificate("rootCA"); serverX509Cert = (X509Certificate) serverKeyStore.getCertificate("server"); serverX509CertSelfSigned = (X509Certificate) serverKeyStore.getCertificate("server_self_signed"); + serverIntX509CertSelfSigned = (X509Certificate) serverKeyStore.getCertificate("serverInt_self_signed"); + serverIntX509CertChain = X509Util.asX509Certificates(serverKeyStore.getCertificateChain("serverint")); trustedCertificates[0] = rootCAX509Cert; - + clientTrustStore = Arrays.asList(new Certificate[] { rootCAX509Cert }); } catch (GeneralSecurityException | IOException e) { throw new RuntimeException(e); } @@ -333,6 +358,38 @@ public void createX509CertClient(Certificate clientCertificate, PrivateKey priva setupClientMonitoring(); } + public void createX509CertClient(X509Certificate[] clientCertificate, PrivateKey privatekey, + List clientTrustStore, X509Certificate serverCertificate, CertificateUsage certificateUsage) + throws CertificateEncodingException { + /* Make sure there is only 1 certificate in chain before client certificate chains are supported */ + assert (clientCertificate.length == 1); + + ObjectsInitializer initializer = new ObjectsInitializer(); + initializer.setInstancesForObject(LwM2mId.SECURITY, + Security.x509( + "coaps://" + server.getSecuredAddress().getHostString() + ":" + + server.getSecuredAddress().getPort(), + 12345, clientCertificate[0].getEncoded(), privatekey.getEncoded(), + serverCertificate.getEncoded(), certificateUsage.code)); + initializer.setInstancesForObject(LwM2mId.SERVER, new Server(12345, LIFETIME)); + initializer.setInstancesForObject(LwM2mId.DEVICE, new Device("Eclipse Leshan", MODEL_NUMBER, "12345")); + initializer.setClassForObject(LwM2mId.ACCESS_CONTROL, DummyInstanceEnabler.class); + List objects = initializer.createAll(); + + InetSocketAddress clientAddress = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0); + LeshanClientBuilder builder = new LeshanClientBuilder(getCurrentEndpoint()); + builder.setLocalAddress(clientAddress.getHostString(), clientAddress.getPort()); + builder.setTrustStore(clientTrustStore); + + Builder dtlsConfig = new DtlsConnectorConfig.Builder(); + dtlsConfig.setClientOnly(); + builder.setDtlsConfig(dtlsConfig); + + builder.setObjects(objects); + client = builder.build(); + setupClientMonitoring(); + } + @Override protected LeshanServerBuilder createServerBuilder() { return createServerBuilder(null); @@ -367,9 +424,19 @@ public void createServerWithX509Cert() { } public void createServerWithX509Cert(X509Certificate serverCertificate, PrivateKey privateKey, Boolean serverOnly) { + createServerWithX509Cert(new X509Certificate[] { serverCertificate }, privateKey, serverOnly); + } + + public void createServerWithX509Cert(X509Certificate serverCertificateChain[], PrivateKey privateKey, + Boolean serverOnly) { + createServerWithX509Cert(serverCertificateChain, privateKey, this.trustedCertificates, serverOnly); + } + + public void createServerWithX509Cert(X509Certificate serverCertificateChain[], PrivateKey privateKey, + Certificate[] trustedCertificates, Boolean serverOnly) { LeshanServerBuilder builder = createServerBuilder(serverOnly); builder.setPrivateKey(privateKey); - builder.setCertificateChain(new X509Certificate[] { serverCertificate }); + builder.setCertificateChain(serverCertificateChain); builder.setTrustedCertificates(trustedCertificates); builder.setAuthorizer(new DefaultAuthorizer(securityStore, new SecurityChecker() { @Override diff --git a/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/SecurityTest.java b/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/SecurityTest.java index d8d6969353..2c50b6ccf7 100644 --- a/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/SecurityTest.java +++ b/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/SecurityTest.java @@ -23,6 +23,7 @@ import java.security.PrivateKey; import java.security.PublicKey; import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; import org.eclipse.californium.core.coap.CoAP.Type; import org.eclipse.californium.core.coap.Request; @@ -38,6 +39,7 @@ import org.eclipse.californium.elements.util.SimpleMessageCallback; import org.eclipse.californium.scandium.DTLSConnector; import org.eclipse.californium.scandium.dtls.DTLSSession; +import org.eclipse.leshan.core.CertificateUsage; import org.eclipse.leshan.core.request.ReadRequest; import org.eclipse.leshan.core.request.exception.SendFailedException; import org.eclipse.leshan.core.request.exception.TimeoutException; @@ -692,6 +694,896 @@ public void registered_device_with_selfsigned_x509cert_to_server_with_x509cert() helper.ensureNoRegistration(1); } + /* ---- CA_CONSTRAINT ---- */ + + /** + *
+     * Test scenario:
+     * - Certificate Usage = CA constraint
+     * - Server Certificate = server certificate
+     * - Server's TLS Server Certificate = intermediate signed certificate (with SAN DNS entry)
+     * - Server accepts client
+     * - Client Trust Store = root CA
+     *
+     * Expected outcome:
+     * - Client denied the connection  (direct trust is not allowed with "CA constraint" usage)
+     * 
+ */ + @Test + public void registered_device_with_x509cert_to_server_with_x509cert_rootca_certificate_usage_ca() + throws NonUniqueSecurityInfoException, CertificateEncodingException { + helper.createServerWithX509Cert(helper.serverIntX509CertChain, helper.serverIntPrivateKeyFromCert, + helper.trustedCertificates, true); + + helper.server.start(); + + helper.setEndpointNameFromX509(helper.clientX509Cert); + + helper.createX509CertClient(new X509Certificate[] { helper.clientX509Cert }, helper.clientPrivateKeyFromCert, + helper.clientTrustStore, helper.serverIntX509CertChain[0], CertificateUsage.CA_CONSTRAINT); + + helper.getSecurityStore().add(SecurityInfo.newX509CertInfo(helper.getCurrentEndpoint())); + + helper.assertClientNotRegisterered(); + helper.client.start(); + helper.ensureNoRegistration(1); + } + + /** + *
+     * Test scenario:
+     * - Certificate Usage = CA constraint
+     * - Server Certificate = intermediate CA certificate
+     * - Server's TLS Server Certificate = intermediate signed certificate (with SAN DNS entry)
+     * - Server accepts client
+     * - Client Trust Store = root CA
+     *
+     * Expected outcome:
+     * - Client is able to connect (intermediate CA cert is part of the chain)
+     * 
+ */ + @Test + public void registered_device_with_x509cert_to_server_with_x509cert_rootca_certificate_usage_ca_intca_given() + throws NonUniqueSecurityInfoException, CertificateEncodingException { + helper.createServerWithX509Cert(helper.serverIntX509CertChain, helper.serverIntPrivateKeyFromCert, + helper.trustedCertificates, true); + + helper.server.start(); + + helper.setEndpointNameFromX509(helper.clientX509Cert); + + helper.createX509CertClient(new X509Certificate[] { helper.clientX509Cert }, helper.clientPrivateKeyFromCert, + helper.clientTrustStore, helper.serverIntX509CertChain[1], CertificateUsage.CA_CONSTRAINT); + + helper.getSecurityStore().add(SecurityInfo.newX509CertInfo(helper.getCurrentEndpoint())); + + helper.assertClientNotRegisterered(); + helper.client.start(); + helper.waitForRegistrationAtServerSide(1); + + assertNotNull(helper.getCurrentRegistration()); + } + + /** + *
+     * Test scenario:
+     * - Certificate Usage = CA constraint
+     * - Server Certificate = root CA certificate (not end-entity certificate)
+     * - Server's TLS Server Certificate = intermediate signed certificate (with SAN DNS entry)
+     * - Server accepts client
+     * - Client Trust Store = root CA
+     *
+     * Expected outcome:
+     * - Client is able to connect (root CA cert is part of the chain)
+     * 
+ */ + @Test + public void registered_device_with_x509cert_to_server_with_x509cert_rootca_certificate_ca_domain_root_ca_given() + throws NonUniqueSecurityInfoException, CertificateEncodingException { + helper.createServerWithX509Cert(helper.serverIntX509CertChain, helper.serverIntPrivateKeyFromCert, + helper.trustedCertificates, true); + + helper.server.start(); + + helper.setEndpointNameFromX509(helper.clientX509Cert); + + helper.createX509CertClient(new X509Certificate[] { helper.clientX509Cert }, helper.clientPrivateKeyFromCert, + helper.clientTrustStore, helper.rootCAX509Cert, CertificateUsage.CA_CONSTRAINT); + + helper.getSecurityStore().add(SecurityInfo.newX509CertInfo(helper.getCurrentEndpoint())); + + helper.assertClientNotRegisterered(); + helper.client.start(); + helper.waitForRegistrationAtServerSide(1); + + assertNotNull(helper.getCurrentRegistration()); + } + + /** + *
+     * Test scenario:
+     * - Certificate Usage = CA constraint
+     * - Server Certificate = other end-entity certificate with same dns name signed by same root ca
+     * - Server's TLS Server Certificate = intermediate signed certificate (with SAN DNS entry)
+     * - Server accepts client
+     * - Client Trust Store = root CA
+     *
+     * Expected outcome:
+     * - Client denied the connection
+     * 
+ */ + @Test + public void registered_device_with_x509cert_to_server_with_x509cert_rootca_certificate_usage_ca_other_server_cert_given() + throws NonUniqueSecurityInfoException, CertificateEncodingException { + helper.createServerWithX509Cert(helper.serverIntX509CertChain, helper.serverIntPrivateKeyFromCert, + helper.trustedCertificates, true); + + helper.server.start(); + + helper.setEndpointNameFromX509(helper.clientX509Cert); + + helper.createX509CertClient(new X509Certificate[] { helper.clientX509Cert }, helper.clientPrivateKeyFromCert, + helper.clientTrustStore, helper.serverX509Cert, CertificateUsage.CA_CONSTRAINT); + + helper.getSecurityStore().add(SecurityInfo.newX509CertInfo(helper.getCurrentEndpoint())); + + helper.assertClientNotRegisterered(); + helper.client.start(); + helper.ensureNoRegistration(1); + } + + /** + *
+     * Test scenario:
+     * - Certificate Usage = CA constraint
+     * - Server Certificate = self signed certificate given
+     * - Server's TLS Server Certificate = intermediate signed certificate (with SAN DNS entry)
+     * - Server accepts client
+     * - Client Trust Store = root CA
+     *
+     * Expected outcome:
+     * - Client denied the connection
+     * 
+ */ + @Test + public void registered_device_with_x509cert_to_server_with_x509cert_rootca_certificate_usage_ca_selfsigned_server_cert_given() + throws NonUniqueSecurityInfoException, CertificateEncodingException { + helper.createServerWithX509Cert(helper.serverIntX509CertChain, helper.serverIntPrivateKeyFromCert, + helper.trustedCertificates, true); + + helper.server.start(); + + helper.setEndpointNameFromX509(helper.clientX509Cert); + + helper.createX509CertClient(new X509Certificate[] { helper.clientX509Cert }, helper.clientPrivateKeyFromCert, + helper.clientTrustStore, helper.serverIntX509CertSelfSigned, CertificateUsage.CA_CONSTRAINT); + + helper.getSecurityStore().add(SecurityInfo.newX509CertInfo(helper.getCurrentEndpoint())); + + helper.assertClientNotRegisterered(); + helper.client.start(); + helper.ensureNoRegistration(1); + } + + /** + *
+     * Test scenario:
+     * - Certificate Usage = CA constraint
+     * - Server Certificate = self signed certificate
+     * - Server's TLS Server Certificate = self signed certificate (with SAN DNS entry)
+     * - Server accepts client
+     * - Client Trust Store = root CA
+     *
+     * Expected outcome:
+     * - Client denied the connection  (direct trust is not allowed with "CA constraint" usage)
+     * 
+ */ + @Test + public void registered_device_with_x509cert_to_server_with_x509cert_selfsigned_certificate_usage_ca_selfsigned_server_cert_given() + throws NonUniqueSecurityInfoException, CertificateEncodingException { + helper.createServerWithX509Cert(new X509Certificate[] { helper.serverIntX509CertSelfSigned }, + helper.serverIntPrivateKeyFromCert, helper.trustedCertificates, true); + + helper.server.start(); + + helper.setEndpointNameFromX509(helper.clientX509Cert); + + helper.createX509CertClient(new X509Certificate[] { helper.clientX509Cert }, helper.clientPrivateKeyFromCert, + helper.clientTrustStore, helper.serverIntX509CertSelfSigned, CertificateUsage.CA_CONSTRAINT); + + helper.getSecurityStore().add(SecurityInfo.newX509CertInfo(helper.getCurrentEndpoint())); + + helper.assertClientNotRegisterered(); + helper.client.start(); + helper.ensureNoRegistration(1); + } + + /** + *
+     * Test scenario:
+     * - Certificate Usage = CA constraint
+     * - Server Certificate = intermediate signed certificate/wo chain
+     * - Server's TLS Server Certificate = intermediate signed certificate/wo chain (with SAN DNS entry)
+     * - Server accepts client
+     * - Client Trust Store = root CA
+     *
+     * Expected outcome:
+     * - Client denied the connection  (direct trust is not allowed with "CA constraint" usage)
+     * 
+ */ + @Test + public void registered_device_with_x509cert_to_server_with_x509cert_server_certificate_usage_ca_server_cert_wo_chain_given() + throws NonUniqueSecurityInfoException, CertificateEncodingException { + helper.createServerWithX509Cert(new X509Certificate[] { helper.serverIntX509CertChain[0] }, + helper.serverIntPrivateKeyFromCert, helper.trustedCertificates, true); + + helper.server.start(); + + helper.setEndpointNameFromX509(helper.clientX509Cert); + + helper.createX509CertClient(new X509Certificate[] { helper.clientX509Cert }, helper.clientPrivateKeyFromCert, + helper.clientTrustStore, helper.serverIntX509CertChain[0], CertificateUsage.CA_CONSTRAINT); + + helper.getSecurityStore().add(SecurityInfo.newX509CertInfo(helper.getCurrentEndpoint())); + + helper.assertClientNotRegisterered(); + helper.client.start(); + helper.ensureNoRegistration(1); + } + + /* ---- SERVICE_CERTIFICATE_CONSTRAINT ---- */ + + /** + *
+     * Test scenario:
+     * - Certificate Usage = service certificate constraint
+     * - Server Certificate = server certificate
+     * - Server's TLS Server Certificate = intermediate signed certificate (with SAN DNS entry)
+     * - Server accepts client
+     * - Client Trust Store = root CA
+     *
+     * Expected outcome:
+     * - Client is able to connect
+     * 
+ */ + @Test + public void registered_device_with_x509cert_to_server_with_x509cert_rootca_certificate_usage_service() + throws NonUniqueSecurityInfoException, CertificateEncodingException { + helper.createServerWithX509Cert(helper.serverIntX509CertChain, helper.serverIntPrivateKeyFromCert, + helper.trustedCertificates, true); + + helper.server.start(); + + helper.setEndpointNameFromX509(helper.clientX509Cert); + + helper.createX509CertClient(new X509Certificate[] { helper.clientX509Cert }, helper.clientPrivateKeyFromCert, + helper.clientTrustStore, helper.serverIntX509CertChain[0], + CertificateUsage.SERVICE_CERTIFICATE_CONSTRAINT); + + helper.getSecurityStore().add(SecurityInfo.newX509CertInfo(helper.getCurrentEndpoint())); + + helper.assertClientNotRegisterered(); + helper.client.start(); + helper.waitForRegistrationAtServerSide(1); + + assertNotNull(helper.getCurrentRegistration()); + } + + /** + *
+     * Test scenario:
+     * - Certificate Usage = service certificate constraint
+     * - Server Certificate = root CA certificate (not end-entity certificate)
+     * - Server's TLS Server Certificate = intermediate signed certificate (with SAN DNS entry)
+     * - Server accepts client
+     * - Client Trust Store = root CA
+     *
+     * Expected outcome:
+     * - Client denied the connection
+     * 
+ */ + @Test + public void registered_device_with_x509cert_to_server_with_x509cert_rootca_certificate_service_domain_root_ca_given() + throws NonUniqueSecurityInfoException, CertificateEncodingException { + helper.createServerWithX509Cert(helper.serverIntX509CertChain, helper.serverIntPrivateKeyFromCert, + helper.trustedCertificates, true); + + helper.server.start(); + + helper.setEndpointNameFromX509(helper.clientX509Cert); + + helper.createX509CertClient(new X509Certificate[] { helper.clientX509Cert }, helper.clientPrivateKeyFromCert, + helper.clientTrustStore, helper.rootCAX509Cert, CertificateUsage.SERVICE_CERTIFICATE_CONSTRAINT); + + helper.getSecurityStore().add(SecurityInfo.newX509CertInfo(helper.getCurrentEndpoint())); + + helper.assertClientNotRegisterered(); + helper.client.start(); + helper.ensureNoRegistration(1); + } + + /** + *
+     * Test scenario:
+     * - Certificate Usage = service certificate constraint
+     * - Server Certificate = other end-entity certificate with same dns name signed by same root ca
+     * - Server's TLS Server Certificate = intermediate signed certificate (with SAN DNS entry)
+     * - Server accepts client
+     * - Client Trust Store = root CA
+     *
+     * Expected outcome:
+     * - Client denied the connection
+     * 
+ */ + @Test + public void registered_device_with_x509cert_to_server_with_x509cert_rootca_certificate_usage_service_other_server_cert_given() + throws NonUniqueSecurityInfoException, CertificateEncodingException { + helper.createServerWithX509Cert(helper.serverIntX509CertChain, helper.serverIntPrivateKeyFromCert, + helper.trustedCertificates, true); + + helper.server.start(); + + helper.setEndpointNameFromX509(helper.clientX509Cert); + + helper.createX509CertClient(new X509Certificate[] { helper.clientX509Cert }, helper.clientPrivateKeyFromCert, + helper.clientTrustStore, helper.serverX509Cert, CertificateUsage.SERVICE_CERTIFICATE_CONSTRAINT); + + helper.getSecurityStore().add(SecurityInfo.newX509CertInfo(helper.getCurrentEndpoint())); + + helper.assertClientNotRegisterered(); + helper.client.start(); + helper.ensureNoRegistration(1); + } + + /** + *
+     * Test scenario:
+     * - Certificate Usage = service certificate constraint
+     * - Server Certificate = self signed certificate given
+     * - Server's TLS Server Certificate = intermediate signed certificate (with SAN DNS entry)
+     * - Server accepts client
+     * - Client Trust Store = root CA
+     *
+     * Expected outcome:
+     * - Client denied the connection
+     * 
+ */ + @Test + public void registered_device_with_x509cert_to_server_with_x509cert_rootca_certificate_usage_service_selfsigned_server_cert_given() + throws NonUniqueSecurityInfoException, CertificateEncodingException { + helper.createServerWithX509Cert(helper.serverIntX509CertChain, helper.serverIntPrivateKeyFromCert, + helper.trustedCertificates, true); + + helper.server.start(); + + helper.setEndpointNameFromX509(helper.clientX509Cert); + + helper.createX509CertClient(new X509Certificate[] { helper.clientX509Cert }, helper.clientPrivateKeyFromCert, + helper.clientTrustStore, helper.serverIntX509CertSelfSigned, + CertificateUsage.SERVICE_CERTIFICATE_CONSTRAINT); + + helper.getSecurityStore().add(SecurityInfo.newX509CertInfo(helper.getCurrentEndpoint())); + + helper.assertClientNotRegisterered(); + helper.client.start(); + helper.ensureNoRegistration(1); + } + + /** + *
+     * Test scenario:
+     * - Certificate Usage = service certificate constraint
+     * - Server Certificate = self signed certificate
+     * - Server's TLS Server Certificate = self signed certificate (with SAN DNS entry)
+     * - Server accepts client
+     * - Client Trust Store = root CA
+     *
+     * Expected outcome:
+     * - Client denied the connection (self-signed is not PKIX chainable)
+     * 
+ */ + @Test + public void registered_device_with_x509cert_to_server_with_x509cert_selfsigned_certificate_usage_service_selfsigned_server_cert_given() + throws NonUniqueSecurityInfoException, CertificateEncodingException { + helper.createServerWithX509Cert(new X509Certificate[] { helper.serverIntX509CertSelfSigned }, + helper.serverIntPrivateKeyFromCert, helper.trustedCertificates, true); + + helper.server.start(); + + helper.setEndpointNameFromX509(helper.clientX509Cert); + + helper.createX509CertClient(new X509Certificate[] { helper.clientX509Cert }, helper.clientPrivateKeyFromCert, + helper.clientTrustStore, helper.serverIntX509CertSelfSigned, + CertificateUsage.SERVICE_CERTIFICATE_CONSTRAINT); + + helper.getSecurityStore().add(SecurityInfo.newX509CertInfo(helper.getCurrentEndpoint())); + + helper.assertClientNotRegisterered(); + helper.client.start(); + helper.ensureNoRegistration(1); + } + + /** + *
+     * Test scenario:
+     * - Certificate Usage = service certificate constraint
+     * - Server Certificate = intermediate signed certificate/wo chain
+     * - Server's TLS Server Certificate = intermediate signed certificate/wo chain (with SAN DNS entry)
+     * - Server accepts client
+     * - Client Trust Store = root CA
+     *
+     * Expected outcome:
+     * - Client denied the connection (missing intermediate CA aka. "server chain configuration problem")
+     * 
+ */ + @Test + public void registered_device_with_x509cert_to_server_with_x509cert_server_certificate_usage_service_server_cert_wo_chain_given() + throws NonUniqueSecurityInfoException, CertificateEncodingException { + helper.createServerWithX509Cert(new X509Certificate[] { helper.serverIntX509CertChain[0] }, + helper.serverIntPrivateKeyFromCert, helper.trustedCertificates, true); + + helper.server.start(); + + helper.setEndpointNameFromX509(helper.clientX509Cert); + + helper.createX509CertClient(new X509Certificate[] { helper.clientX509Cert }, helper.clientPrivateKeyFromCert, + helper.clientTrustStore, helper.serverIntX509CertChain[0], + CertificateUsage.SERVICE_CERTIFICATE_CONSTRAINT); + + helper.getSecurityStore().add(SecurityInfo.newX509CertInfo(helper.getCurrentEndpoint())); + + helper.assertClientNotRegisterered(); + helper.client.start(); + helper.ensureNoRegistration(1); + } + + /* ---- TRUST_ANCHOR_ASSERTION ---- */ + + /** + *
+     * Test scenario:
+     * - Certificate Usage = trust anchor assertion
+     * - Server Certificate = server certificate
+     * - Server's TLS Server Certificate = intermediate signed certificate (with SAN DNS entry)
+     * - Server accepts client
+     * - Client Trust Store = root CA
+     *
+     * Expected outcome:
+     * - Client denied the connection  (direct trust is not allowed with "trust constraint" usage)
+     * 
+ */ + @Test + public void registered_device_with_x509cert_to_server_with_x509cert_rootca_certificate_usage_taa() + throws NonUniqueSecurityInfoException, CertificateEncodingException { + helper.createServerWithX509Cert(helper.serverIntX509CertChain, helper.serverIntPrivateKeyFromCert, + helper.trustedCertificates, true); + + helper.server.start(); + + helper.setEndpointNameFromX509(helper.clientX509Cert); + + helper.createX509CertClient(new X509Certificate[] { helper.clientX509Cert }, helper.clientPrivateKeyFromCert, + helper.clientTrustStore, helper.serverIntX509CertChain[0], CertificateUsage.TRUST_ANCHOR_ASSERTION); + + helper.getSecurityStore().add(SecurityInfo.newX509CertInfo(helper.getCurrentEndpoint())); + + helper.assertClientNotRegisterered(); + helper.client.start(); + helper.ensureNoRegistration(1); + } + + /** + *
+     * Test scenario:
+     * - Certificate Usage = trust anchor assertion
+     * - Server Certificate = intermediate CA certificate
+     * - Server's TLS Server Certificate = intermediate signed certificate (with SAN DNS entry)
+     * - Server accepts client
+     * - Client Trust Store = root CA
+     *
+     * Expected outcome:
+     * - Client is able to connect (pkix path terminates in intermediate CA (TA), root CA is not available as client trust store not in use)
+     * 
+ */ + @Test + public void registered_device_with_x509cert_to_server_with_x509cert_rootca_certificate_usage_taa_intca_given() + throws NonUniqueSecurityInfoException, CertificateEncodingException { + helper.createServerWithX509Cert(helper.serverIntX509CertChain, helper.serverIntPrivateKeyFromCert, + helper.trustedCertificates, true); + + helper.server.start(); + + helper.setEndpointNameFromX509(helper.clientX509Cert); + + helper.createX509CertClient(new X509Certificate[] { helper.clientX509Cert }, helper.clientPrivateKeyFromCert, + helper.clientTrustStore, helper.serverIntX509CertChain[1], CertificateUsage.TRUST_ANCHOR_ASSERTION); + + helper.getSecurityStore().add(SecurityInfo.newX509CertInfo(helper.getCurrentEndpoint())); + + helper.assertClientNotRegisterered(); + helper.client.start(); + helper.waitForRegistrationAtServerSide(1); + + assertNotNull(helper.getCurrentRegistration()); + } + + /** + *
+     * Test scenario:
+     * - Certificate Usage = trust anchor assertion
+     * - Server Certificate = root CA certificate
+     * - Server's TLS Server Certificate = intermediate signed certificate (with SAN DNS entry)
+     * - Server accepts client
+     * - Client Trust Store = root CA
+     *
+     * Expected outcome:
+     * - Client is able to connect (root CA cert is part of the chain)
+     * 
+ */ + @Test + public void registered_device_with_x509cert_to_server_with_x509cert_rootca_certificate_taa_domain_root_ca_given() + throws NonUniqueSecurityInfoException, CertificateEncodingException { + helper.createServerWithX509Cert(helper.serverIntX509CertChain, helper.serverIntPrivateKeyFromCert, + helper.trustedCertificates, true); + + helper.server.start(); + + helper.setEndpointNameFromX509(helper.clientX509Cert); + + helper.createX509CertClient(new X509Certificate[] { helper.clientX509Cert }, helper.clientPrivateKeyFromCert, + helper.clientTrustStore, helper.rootCAX509Cert, CertificateUsage.TRUST_ANCHOR_ASSERTION); + + helper.getSecurityStore().add(SecurityInfo.newX509CertInfo(helper.getCurrentEndpoint())); + + helper.assertClientNotRegisterered(); + helper.client.start(); + helper.waitForRegistrationAtServerSide(1); + + assertNotNull(helper.getCurrentRegistration()); + } + + /** + *
+     * Test scenario:
+     * - Certificate Usage = trust anchor assertion
+     * - Server Certificate = other end-entity certificate with same dns name signed by same root ca
+     * - Server's TLS Server Certificate = intermediate signed certificate (with SAN DNS entry)
+     * - Server accepts client
+     * - Client Trust Store = root CA
+     *
+     * Expected outcome:
+     * - Client denied the connection
+     * 
+ */ + @Test + public void registered_device_with_x509cert_to_server_with_x509cert_rootca_certificate_usage_taa_other_server_cert_given() + throws NonUniqueSecurityInfoException, CertificateEncodingException { + helper.createServerWithX509Cert(helper.serverIntX509CertChain, helper.serverIntPrivateKeyFromCert, + helper.trustedCertificates, true); + + helper.server.start(); + + helper.setEndpointNameFromX509(helper.clientX509Cert); + + helper.createX509CertClient(new X509Certificate[] { helper.clientX509Cert }, helper.clientPrivateKeyFromCert, + helper.clientTrustStore, helper.serverX509Cert, CertificateUsage.TRUST_ANCHOR_ASSERTION); + + helper.getSecurityStore().add(SecurityInfo.newX509CertInfo(helper.getCurrentEndpoint())); + + helper.assertClientNotRegisterered(); + helper.client.start(); + helper.ensureNoRegistration(1); + } + + /** + *
+     * Test scenario:
+     * - Certificate Usage = trust anchor assertion
+     * - Server Certificate = self signed certificate given
+     * - Server's TLS Server Certificate = intermediate signed certificate (with SAN DNS entry)
+     * - Server accepts client
+     * - Client Trust Store = root CA
+     *
+     * Expected outcome:
+     * - Client denied the connection
+     * 
+ */ + @Test + public void registered_device_with_x509cert_to_server_with_x509cert_rootca_certificate_usage_taa_selfsigned_server_cert_given() + throws NonUniqueSecurityInfoException, CertificateEncodingException { + helper.createServerWithX509Cert(helper.serverIntX509CertChain, helper.serverIntPrivateKeyFromCert, + helper.trustedCertificates, true); + + helper.server.start(); + + helper.setEndpointNameFromX509(helper.clientX509Cert); + + helper.createX509CertClient(new X509Certificate[] { helper.clientX509Cert }, helper.clientPrivateKeyFromCert, + helper.clientTrustStore, helper.serverIntX509CertSelfSigned, CertificateUsage.TRUST_ANCHOR_ASSERTION); + + helper.getSecurityStore().add(SecurityInfo.newX509CertInfo(helper.getCurrentEndpoint())); + + helper.assertClientNotRegisterered(); + helper.client.start(); + helper.ensureNoRegistration(1); + } + + /** + *
+     * Test scenario:
+     * - Certificate Usage = trust anchor assertion
+     * - Server Certificate = self signed certificate
+     * - Server's TLS Server Certificate = self signed certificate (with SAN DNS entry)
+     * - Server accepts client
+     * - Client Trust Store = root CA
+     *
+     * Expected outcome:
+     * - Client denied the connection  (direct trust is not allowed with "trust anchor" usage)
+     * 
+ */ + @Test + public void registered_device_with_x509cert_to_server_with_x509cert_selfsigned_certificate_usage_taa_selfsigned_server_cert_given() + throws NonUniqueSecurityInfoException, CertificateEncodingException { + helper.createServerWithX509Cert(new X509Certificate[] { helper.serverIntX509CertSelfSigned }, + helper.serverIntPrivateKeyFromCert, helper.trustedCertificates, true); + + helper.server.start(); + + helper.setEndpointNameFromX509(helper.clientX509Cert); + + helper.createX509CertClient(new X509Certificate[] { helper.clientX509Cert }, helper.clientPrivateKeyFromCert, + helper.clientTrustStore, helper.serverIntX509CertSelfSigned, CertificateUsage.TRUST_ANCHOR_ASSERTION); + + helper.getSecurityStore().add(SecurityInfo.newX509CertInfo(helper.getCurrentEndpoint())); + + helper.assertClientNotRegisterered(); + helper.client.start(); + helper.ensureNoRegistration(1); + } + + /** + *
+     * Test scenario:
+     * - Certificate Usage = trust anchor assertion
+     * - Server Certificate = intermediate signed certificate/wo chain
+     * - Server's TLS Server Certificate = intermediate signed certificate/wo chain (with SAN DNS entry)
+     * - Server accepts client
+     * - Client Trust Store = root CA
+     *
+     * Expected outcome:
+     * - Client denied the connection  (direct trust is not allowed with "trust anchor" usage)
+     * 
+ */ + @Test + public void registered_device_with_x509cert_to_server_with_x509cert_server_certificate_usage_taa_server_cert_wo_chain_given() + throws NonUniqueSecurityInfoException, CertificateEncodingException { + helper.createServerWithX509Cert(new X509Certificate[] { helper.serverIntX509CertChain[0] }, + helper.serverIntPrivateKeyFromCert, helper.trustedCertificates, true); + + helper.server.start(); + + helper.setEndpointNameFromX509(helper.clientX509Cert); + + helper.createX509CertClient(new X509Certificate[] { helper.clientX509Cert }, helper.clientPrivateKeyFromCert, + helper.clientTrustStore, helper.serverIntX509CertChain[0], CertificateUsage.TRUST_ANCHOR_ASSERTION); + + helper.getSecurityStore().add(SecurityInfo.newX509CertInfo(helper.getCurrentEndpoint())); + + helper.assertClientNotRegisterered(); + helper.client.start(); + helper.ensureNoRegistration(1); + } + + /* ---- DOMAIN_ISSUER_CERTIFICATE ---- */ + + /** + *
+     * Test scenario:
+     * - Certificate Usage = domain issuer certificate
+     * - Server Certificate = server certificate
+     * - Server's TLS Server Certificate = intermediate signed certificate (with SAN DNS entry)
+     * - Server accepts client
+     * - Client Trust Store = root CA
+     *
+     * Expected outcome:
+     * - Client is able to connect
+     * 
+ */ + @Test + public void registered_device_with_x509cert_to_server_with_x509cert_rootca_certificate_usage_domain() + throws NonUniqueSecurityInfoException, CertificateEncodingException { + helper.createServerWithX509Cert(helper.serverIntX509CertChain, helper.serverIntPrivateKeyFromCert, + helper.trustedCertificates, true); + + helper.server.start(); + + helper.setEndpointNameFromX509(helper.clientX509Cert); + + helper.createX509CertClient(new X509Certificate[] { helper.clientX509Cert }, helper.clientPrivateKeyFromCert, + helper.clientTrustStore, helper.serverIntX509CertChain[0], CertificateUsage.DOMAIN_ISSUER_CERTIFICATE); + + helper.getSecurityStore().add(SecurityInfo.newX509CertInfo(helper.getCurrentEndpoint())); + + helper.assertClientNotRegisterered(); + helper.client.start(); + helper.waitForRegistrationAtServerSide(1); + + assertNotNull(helper.getCurrentRegistration()); + } + + /** + *
+     * Test scenario:
+     * - Certificate Usage = domain issuer certificate
+     * - Server Certificate = root CA certificate (not end-entity certificate)
+     * - Server's TLS Server Certificate = intermediate signed certificate (with SAN DNS entry)
+     * - Server accepts client
+     * - Client Trust Store = root CA
+     *
+     * Expected outcome:
+     * - Client denied the connection (no end-entity certificate given)
+     * 
+ */ + @Test + public void registered_device_with_x509cert_to_server_with_x509cert_rootca_certificate_usage_domain_root_ca_given() + throws NonUniqueSecurityInfoException, CertificateEncodingException { + helper.createServerWithX509Cert(helper.serverIntX509CertChain, helper.serverIntPrivateKeyFromCert, + helper.trustedCertificates, true); + + helper.server.start(); + + helper.setEndpointNameFromX509(helper.clientX509Cert); + + helper.createX509CertClient(new X509Certificate[] { helper.clientX509Cert }, helper.clientPrivateKeyFromCert, + helper.clientTrustStore, helper.rootCAX509Cert, CertificateUsage.DOMAIN_ISSUER_CERTIFICATE); + + helper.getSecurityStore().add(SecurityInfo.newX509CertInfo(helper.getCurrentEndpoint())); + + helper.assertClientNotRegisterered(); + helper.client.start(); + helper.ensureNoRegistration(1); + } + + /** + *
+     * Test scenario:
+     * - Certificate Usage = domain issuer certificate
+     * - Server Certificate = other end-entity certificate with same dns name signed by same root ca
+     * - Server's TLS Server Certificate = intermediate signed certificate (with SAN DNS entry)
+     * - Server accepts client
+     * - Client Trust Store = root CA
+     *
+     * Expected outcome:
+     * - Client denied the connection (different server cert given even thou hostname matches)
+     * 
+ */ + @Test + public void registered_device_with_x509cert_to_server_with_x509cert_rootca_certificate_usage_domain_other_server_cert_given() + throws NonUniqueSecurityInfoException, CertificateEncodingException { + helper.createServerWithX509Cert(helper.serverIntX509CertChain, helper.serverIntPrivateKeyFromCert, + helper.trustedCertificates, true); + + helper.server.start(); + + helper.setEndpointNameFromX509(helper.clientX509Cert); + + helper.createX509CertClient(new X509Certificate[] { helper.clientX509Cert }, helper.clientPrivateKeyFromCert, + helper.clientTrustStore, helper.serverX509Cert, CertificateUsage.DOMAIN_ISSUER_CERTIFICATE); + + helper.getSecurityStore().add(SecurityInfo.newX509CertInfo(helper.getCurrentEndpoint())); + + helper.assertClientNotRegisterered(); + helper.client.start(); + helper.ensureNoRegistration(1); + } + + /** + *
+     * Test scenario:
+     * - Certificate Usage = domain issuer certificate
+     * - Server Certificate = self signed certificate given
+     * - Server's TLS Server Certificate = intermediate signed certificate (with SAN DNS entry)
+     * - Server accepts client
+     * - Client Trust Store = root CA
+     *
+     * Expected outcome:
+     * - Client denied the connection (different certificate self-signed vs. signed -- even thou the public key is same)
+     * 
+ */ + @Test + public void registered_device_with_x509cert_to_server_with_x509cert_rootca_certificate_usage_domain_selfsigned_server_cert_given() + throws NonUniqueSecurityInfoException, CertificateEncodingException { + helper.createServerWithX509Cert(helper.serverIntX509CertChain, helper.serverIntPrivateKeyFromCert, + helper.trustedCertificates, true); + + helper.server.start(); + + helper.setEndpointNameFromX509(helper.clientX509Cert); + + helper.createX509CertClient(new X509Certificate[] { helper.clientX509Cert }, helper.clientPrivateKeyFromCert, + helper.clientTrustStore, helper.serverIntX509CertSelfSigned, + CertificateUsage.DOMAIN_ISSUER_CERTIFICATE); + + helper.getSecurityStore().add(SecurityInfo.newX509CertInfo(helper.getCurrentEndpoint())); + + helper.assertClientNotRegisterered(); + helper.client.start(); + helper.ensureNoRegistration(1); + } + + /** + *
+     * Test scenario:
+     * - Certificate Usage = domain issuer certificate
+     * - Server Certificate = self signed certificate
+     * - Server's TLS Server Certificate = self signed certificate (with SAN DNS entry)
+     * - Server accepts client
+     * - Client Trust Store = root CA
+     *
+     * Expected outcome:
+     * - Client is able to connect
+     * 
+ */ + @Test + public void registered_device_with_x509cert_to_server_with_x509cert_selfsigned_certificate_usage_domain_selfsigned_server_cert_given() + throws NonUniqueSecurityInfoException, CertificateEncodingException { + helper.createServerWithX509Cert(new X509Certificate[] { helper.serverIntX509CertSelfSigned }, + helper.serverIntPrivateKeyFromCert, helper.trustedCertificates, true); + + helper.server.start(); + + helper.setEndpointNameFromX509(helper.clientX509Cert); + + helper.createX509CertClient(new X509Certificate[] { helper.clientX509Cert }, helper.clientPrivateKeyFromCert, + helper.clientTrustStore, helper.serverIntX509CertSelfSigned, + CertificateUsage.DOMAIN_ISSUER_CERTIFICATE); + + helper.getSecurityStore().add(SecurityInfo.newX509CertInfo(helper.getCurrentEndpoint())); + + helper.assertClientNotRegisterered(); + helper.client.start(); + helper.waitForRegistrationAtServerSide(1); + + assertNotNull(helper.getCurrentRegistration()); + } + + /** + *
+     * Test scenario:
+     * - Certificate Usage = service certificate constraint
+     * - Server Certificate = intermediate signed certificate/wo chain
+     * - Server's TLS Server Certificate = intermediate signed certificate/wo chain (with SAN DNS entry)
+     * - Server accepts client
+     * - Client Trust Store = root CA
+     *
+     * Expected outcome:
+     * - Client is able to connect
+     * 
+ */ + @Test + public void registered_device_with_x509cert_to_server_with_x509cert_server_certificate_usage_domain_server_cert_wo_chain_given() + throws NonUniqueSecurityInfoException, CertificateEncodingException { + helper.createServerWithX509Cert(new X509Certificate[] { helper.serverIntX509CertChain[0] }, + helper.serverIntPrivateKeyFromCert, helper.trustedCertificates, true); + + helper.server.start(); + + helper.setEndpointNameFromX509(helper.clientX509Cert); + + helper.createX509CertClient(new X509Certificate[] { helper.clientX509Cert }, helper.clientPrivateKeyFromCert, + helper.clientTrustStore, helper.serverIntX509CertChain[0], CertificateUsage.DOMAIN_ISSUER_CERTIFICATE); + + helper.getSecurityStore().add(SecurityInfo.newX509CertInfo(helper.getCurrentEndpoint())); + + helper.assertClientNotRegisterered(); + helper.client.start(); + helper.waitForRegistrationAtServerSide(1); + + assertNotNull(helper.getCurrentRegistration()); + } + + /* ---- */ + @Test public void registered_device_with_x509cert_to_server_with_rpk() throws NonUniqueSecurityInfoException, CertificateEncodingException {