From 35ec99cb632c22ac5125093a923fa86f24e4b035 Mon Sep 17 00:00:00 2001 From: Jan Romann Date: Wed, 16 Oct 2024 09:00:11 +0200 Subject: [PATCH 1/7] feat(binding-coap): add support for client certificates --- lib/src/binding_coap/coap_client.dart | 14 +++++++++++++- lib/src/binding_coap/coap_config.dart | 7 +++++++ pubspec.yaml | 6 ++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/lib/src/binding_coap/coap_client.dart b/lib/src/binding_coap/coap_client.dart index cb1ad7d9..49ec6aad 100644 --- a/lib/src/binding_coap/coap_client.dart +++ b/lib/src/binding_coap/coap_client.dart @@ -26,7 +26,10 @@ class _InternalCoapConfig extends CoapConfigDefault { dtlsCiphers = coapConfig.dtlsCiphers, dtlsVerify = coapConfig.dtlsVerify, dtlsWithTrustedRoots = coapConfig.dtlsWithTrustedRoots, - rootCertificates = coapConfig.rootCertificates; + rootCertificates = coapConfig.rootCertificates, + clientCertificateFileName = coapConfig.clientCertificateFileName, + clientKeyFileName = coapConfig.clientKeyFileName, + verifyPrivateKey = coapConfig.verifyPrivateKey; @override final int preferredBlockSize; @@ -42,6 +45,15 @@ class _InternalCoapConfig extends CoapConfigDefault { @override final List rootCertificates; + + @override + final String? clientCertificateFileName; + + @override + final String? clientKeyFileName; + + @override + final bool verifyPrivateKey; } coap.PskCredentialsCallback? _createPskCallback( diff --git a/lib/src/binding_coap/coap_config.dart b/lib/src/binding_coap/coap_config.dart index 462c906d..d9ec0e0f 100644 --- a/lib/src/binding_coap/coap_config.dart +++ b/lib/src/binding_coap/coap_config.dart @@ -22,6 +22,9 @@ class CoapConfig { this.rootCertificates = const [], this.dtlsWithTrustedRoots = true, this.dtlsVerify = true, + this.clientKeyFileName, + this.clientCertificateFileName, + this.verifyPrivateKey = false, }); /// Whether certificates should be verified by OpenSSL. @@ -57,4 +60,8 @@ class CoapConfig { /// /// Defaults to 60 seconds. final Duration multicastDiscoveryTimeout; + + final String? clientCertificateFileName; + final String? clientKeyFileName; + final bool verifyPrivateKey; } diff --git a/pubspec.yaml b/pubspec.yaml index b738ada5..0a6aa655 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -30,3 +30,9 @@ dependencies: typed_data: ^1.3.2 uri: ^1.0.0 uuid: ^4.2.1 + +dependency_overrides: + coap: + git: + url: https://github.com/namib-project/coap + ref: client-certificate-support From fcc451bfc20c7899b0f7518acf8f7495a1f66cac Mon Sep 17 00:00:00 2001 From: Jan Romann Date: Wed, 16 Oct 2024 09:09:53 +0200 Subject: [PATCH 2/7] fixup! feat(binding-coap): add support for client certificates --- lib/src/binding_coap/coap_client.dart | 6 ++++-- lib/src/binding_coap/coap_config.dart | 6 ++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/src/binding_coap/coap_client.dart b/lib/src/binding_coap/coap_client.dart index 49ec6aad..89ef2916 100644 --- a/lib/src/binding_coap/coap_client.dart +++ b/lib/src/binding_coap/coap_client.dart @@ -29,7 +29,7 @@ class _InternalCoapConfig extends CoapConfigDefault { rootCertificates = coapConfig.rootCertificates, clientCertificateFileName = coapConfig.clientCertificateFileName, clientKeyFileName = coapConfig.clientKeyFileName, - verifyPrivateKey = coapConfig.verifyPrivateKey; + _verifyPrivateKey = coapConfig.verifyPrivateKey; @override final int preferredBlockSize; @@ -52,8 +52,10 @@ class _InternalCoapConfig extends CoapConfigDefault { @override final String? clientKeyFileName; + final bool _verifyPrivateKey; + @override - final bool verifyPrivateKey; + bool get verifyPrivateKey => _verifyPrivateKey; } coap.PskCredentialsCallback? _createPskCallback( diff --git a/lib/src/binding_coap/coap_config.dart b/lib/src/binding_coap/coap_config.dart index d9ec0e0f..f98c5583 100644 --- a/lib/src/binding_coap/coap_config.dart +++ b/lib/src/binding_coap/coap_config.dart @@ -61,7 +61,13 @@ class CoapConfig { /// Defaults to 60 seconds. final Duration multicastDiscoveryTimeout; + /// Name of a file referring to a client certificate used with DTLS PKI mode. final String? clientCertificateFileName; + + /// Name of a file referring to a private client key used with DTLS PKI mode. final String? clientKeyFileName; + + /// Whether the private key of the client certificate should be verified when + /// creating the DTLS context. final bool verifyPrivateKey; } From 10f3398444aca6230584c2ba174045669398d94b Mon Sep 17 00:00:00 2001 From: Jan Romann Date: Wed, 16 Oct 2024 09:14:12 +0200 Subject: [PATCH 3/7] fixup! feat(binding-coap): add support for client certificates --- pubspec.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pubspec.yaml b/pubspec.yaml index 0a6aa655..e901c17d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -36,3 +36,7 @@ dependency_overrides: git: url: https://github.com/namib-project/coap ref: client-certificate-support + dtls2: + git: + url: https://github.com/JKRhb/dtls2 + ref: client-certificates From 4148ad5961336f8244413b09e4700562d6681d63 Mon Sep 17 00:00:00 2001 From: Jan Romann Date: Thu, 17 Oct 2024 10:29:00 +0200 Subject: [PATCH 4/7] fixup! feat(binding-coap): add support for client certificates --- lib/src/binding_coap/coap_client.dart | 8 ++++---- lib/src/binding_coap/coap_config.dart | 9 +++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/lib/src/binding_coap/coap_client.dart b/lib/src/binding_coap/coap_client.dart index 89ef2916..39d47cf5 100644 --- a/lib/src/binding_coap/coap_client.dart +++ b/lib/src/binding_coap/coap_client.dart @@ -27,8 +27,8 @@ class _InternalCoapConfig extends CoapConfigDefault { dtlsVerify = coapConfig.dtlsVerify, dtlsWithTrustedRoots = coapConfig.dtlsWithTrustedRoots, rootCertificates = coapConfig.rootCertificates, - clientCertificateFileName = coapConfig.clientCertificateFileName, - clientKeyFileName = coapConfig.clientKeyFileName, + clientCertificate = coapConfig.clientCertificate, + clientPrivateKey = coapConfig.clientPrivateKey, _verifyPrivateKey = coapConfig.verifyPrivateKey; @override @@ -47,10 +47,10 @@ class _InternalCoapConfig extends CoapConfigDefault { final List rootCertificates; @override - final String? clientCertificateFileName; + final coap.ClientCertificate? clientCertificate; @override - final String? clientKeyFileName; + final coap.ClientPrivateKey? clientPrivateKey; final bool _verifyPrivateKey; diff --git a/lib/src/binding_coap/coap_config.dart b/lib/src/binding_coap/coap_config.dart index f98c5583..a1cad6ef 100644 --- a/lib/src/binding_coap/coap_config.dart +++ b/lib/src/binding_coap/coap_config.dart @@ -6,6 +6,7 @@ import "dart:typed_data"; +import "package:coap/coap.dart"; import "package:meta/meta.dart"; /// Allows for configuring the behavior of CoAP clients and servers. @@ -22,8 +23,8 @@ class CoapConfig { this.rootCertificates = const [], this.dtlsWithTrustedRoots = true, this.dtlsVerify = true, - this.clientKeyFileName, - this.clientCertificateFileName, + this.clientCertificate, + this.clientPrivateKey, this.verifyPrivateKey = false, }); @@ -62,10 +63,10 @@ class CoapConfig { final Duration multicastDiscoveryTimeout; /// Name of a file referring to a client certificate used with DTLS PKI mode. - final String? clientCertificateFileName; + final ClientCertificate? clientCertificate; /// Name of a file referring to a private client key used with DTLS PKI mode. - final String? clientKeyFileName; + final ClientPrivateKey? clientPrivateKey; /// Whether the private key of the client certificate should be verified when /// creating the DTLS context. From 30afd8025e1f7a0549c9d3e549b20999b7e98281 Mon Sep 17 00:00:00 2001 From: Jan Romann Date: Thu, 17 Oct 2024 11:25:11 +0200 Subject: [PATCH 5/7] feat: remove CoAP observe subprotocol --- lib/src/binding_coap/coap_client.dart | 14 +++-------- lib/src/binding_coap/coap_client_factory.dart | 8 +----- lib/src/binding_coap/coap_definitions.dart | 17 ------------- lib/src/binding_coap/coap_extensions.dart | 25 ------------------- 4 files changed, 4 insertions(+), 60 deletions(-) diff --git a/lib/src/binding_coap/coap_client.dart b/lib/src/binding_coap/coap_client.dart index 39d47cf5..2a662dfe 100644 --- a/lib/src/binding_coap/coap_client.dart +++ b/lib/src/binding_coap/coap_client.dart @@ -435,22 +435,14 @@ final class CoapClient extends ProtocolClient accept: form.accept, ); - final subprotocol = form.coapSubprotocol ?? operationType.subprotocol; - final coapClient = coap.CoapClient( form.resolvedHref, config: _InternalCoapConfig(_coapConfig ?? const CoapConfig()), ); - if (subprotocol == CoapSubprotocol.observe) { - final observeClientRelation = await coapClient.observe(request); - observeClientRelation.listen(handleResponse); - return CoapSubscription(coapClient, observeClientRelation, complete); - } - - final response = await coapClient.send(request); - handleResponse(response); - return CoapSubscription(coapClient, null, complete); + final observeClientRelation = await coapClient.observe(request); + observeClientRelation.listen(handleResponse); + return CoapSubscription(coapClient, observeClientRelation, complete); } @override diff --git a/lib/src/binding_coap/coap_client_factory.dart b/lib/src/binding_coap/coap_client_factory.dart index 74e1d4d2..1883808d 100644 --- a/lib/src/binding_coap/coap_client_factory.dart +++ b/lib/src/binding_coap/coap_client_factory.dart @@ -8,7 +8,6 @@ import "../../core.dart"; import "coap_client.dart"; import "coap_config.dart"; -import "coap_definitions.dart"; /// A [ProtocolClientFactory] that produces CoAP clients. final class CoapClientFactory implements ProtocolClientFactory { @@ -56,11 +55,6 @@ final class CoapClientFactory implements ProtocolClientFactory { OperationType.unsubscribeevent, ]; - if (observeOperations.contains(operationType)) { - return CoapSubprotocol.tryParse(subprotocol ?? "") == - CoapSubprotocol.observe; - } - - return subprotocol == null; + return observeOperations.contains(operationType); } } diff --git a/lib/src/binding_coap/coap_definitions.dart b/lib/src/binding_coap/coap_definitions.dart index 6be670de..fa9618c8 100644 --- a/lib/src/binding_coap/coap_definitions.dart +++ b/lib/src/binding_coap/coap_definitions.dart @@ -50,20 +50,3 @@ enum CoapRequestMethod { static CoapRequestMethod? fromString(String stringValue) => _registry[stringValue]; } - -/// Enumeration of available CoAP subprotocols. -enum CoapSubprotocol { - /// Subprotocol for observing CoAP resources. - observe, - ; - - /// Tries to match the given [subprotocol] string to one of the known - /// [CoapSubprotocol.values]. - static CoapSubprotocol? tryParse(String subprotocol) { - if (subprotocol == "cov:observe") { - return CoapSubprotocol.observe; - } - - return null; - } -} diff --git a/lib/src/binding_coap/coap_extensions.dart b/lib/src/binding_coap/coap_extensions.dart index 00492b21..ee579ba1 100644 --- a/lib/src/binding_coap/coap_extensions.dart +++ b/lib/src/binding_coap/coap_extensions.dart @@ -36,15 +36,6 @@ extension CoapFormExtension on AugmentedForm { bool get usesAutoScheme => securityDefinitions.whereType().isNotEmpty; - /// Get the [CoapSubprotocol] for this [AugmentedForm], if one is set. - CoapSubprotocol? get coapSubprotocol { - if (subprotocol == coapPrefixMapping.expandCurieString("observe")) { - return CoapSubprotocol.observe; - } - - return null; - } - /// The Content-Format for CoAP request and response payloads. CoapMediaType get contentFormat { final formDefinition = _obtainVocabularyTerm("contentFormat"); @@ -160,22 +151,6 @@ extension OperationTypeExtension on OperationType { return CoapRequestMethod.get; } } - - /// Determines the [CoapSubprotocol] (if any) for this [OperationType]. - /// - /// The only supported subprotocol at the moment is `observe`. - CoapSubprotocol? get subprotocol { - if ([ - OperationType.subscribeevent, - OperationType.unsubscribeevent, - OperationType.observeproperty, - OperationType.unobserveproperty, - ].contains(this)) { - return CoapSubprotocol.observe; - } - - return null; - } } /// Extension for easily extracting the [content] from a [CoapResponse]. From 3517a5b14e0e88ecc9bc4123ed57464141cd3b0b Mon Sep 17 00:00:00 2001 From: Jan Romann Date: Thu, 17 Oct 2024 11:34:14 +0200 Subject: [PATCH 6/7] fixup! feat(binding-coap): add support for client certificates --- lib/binding_coap.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/binding_coap.dart b/lib/binding_coap.dart index f2b33fb7..55875ff9 100644 --- a/lib/binding_coap.dart +++ b/lib/binding_coap.dart @@ -10,6 +10,8 @@ /// [spec link]: https://www.w3.org/TR/wot-binding-templates/ library binding_coap; +export "package:coap/coap.dart" show ClientCertificate, ClientPrivateKey; + export "src/binding_coap/coap_client_factory.dart"; export "src/binding_coap/coap_config.dart"; export "src/binding_coap/coap_server.dart"; From cde435353477c06fcb137a0dcb0ea19afb315059 Mon Sep 17 00:00:00 2001 From: Jan Romann Date: Fri, 18 Oct 2024 12:23:58 +0200 Subject: [PATCH 7/7] feat: allow for overriding the initTimeout --- lib/src/binding_coap/coap_client.dart | 1 + lib/src/binding_coap/coap_config.dart | 3 +++ 2 files changed, 4 insertions(+) diff --git a/lib/src/binding_coap/coap_client.dart b/lib/src/binding_coap/coap_client.dart index 2a662dfe..c90844b1 100644 --- a/lib/src/binding_coap/coap_client.dart +++ b/lib/src/binding_coap/coap_client.dart @@ -175,6 +175,7 @@ final class CoapClient extends ProtocolClient form, pskCredentialsCallback: _pskCredentialsCallback, ), + initTimeout: _coapConfig?.initTimeout ?? const Duration(seconds: 10), ); final request = await _createRequest( diff --git a/lib/src/binding_coap/coap_config.dart b/lib/src/binding_coap/coap_config.dart index a1cad6ef..62d8574b 100644 --- a/lib/src/binding_coap/coap_config.dart +++ b/lib/src/binding_coap/coap_config.dart @@ -26,8 +26,11 @@ class CoapConfig { this.clientCertificate, this.clientPrivateKey, this.verifyPrivateKey = false, + this.initTimeout, }); + final Duration? initTimeout; + /// Whether certificates should be verified by OpenSSL. final bool dtlsVerify;