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"; diff --git a/lib/src/binding_coap/coap_client.dart b/lib/src/binding_coap/coap_client.dart index cb1ad7d9..c90844b1 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, + clientCertificate = coapConfig.clientCertificate, + clientPrivateKey = coapConfig.clientPrivateKey, + _verifyPrivateKey = coapConfig.verifyPrivateKey; @override final int preferredBlockSize; @@ -42,6 +45,17 @@ class _InternalCoapConfig extends CoapConfigDefault { @override final List rootCertificates; + + @override + final coap.ClientCertificate? clientCertificate; + + @override + final coap.ClientPrivateKey? clientPrivateKey; + + final bool _verifyPrivateKey; + + @override + bool get verifyPrivateKey => _verifyPrivateKey; } coap.PskCredentialsCallback? _createPskCallback( @@ -161,6 +175,7 @@ final class CoapClient extends ProtocolClient form, pskCredentialsCallback: _pskCredentialsCallback, ), + initTimeout: _coapConfig?.initTimeout ?? const Duration(seconds: 10), ); final request = await _createRequest( @@ -421,22 +436,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_config.dart b/lib/src/binding_coap/coap_config.dart index 462c906d..62d8574b 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,14 @@ class CoapConfig { this.rootCertificates = const [], this.dtlsWithTrustedRoots = true, this.dtlsVerify = true, + this.clientCertificate, + this.clientPrivateKey, + this.verifyPrivateKey = false, + this.initTimeout, }); + final Duration? initTimeout; + /// Whether certificates should be verified by OpenSSL. final bool dtlsVerify; @@ -57,4 +64,14 @@ class CoapConfig { /// /// Defaults to 60 seconds. final Duration multicastDiscoveryTimeout; + + /// Name of a file referring to a client certificate used with DTLS PKI mode. + final ClientCertificate? clientCertificate; + + /// Name of a file referring to a private client key used with DTLS PKI mode. + final ClientPrivateKey? clientPrivateKey; + + /// Whether the private key of the client certificate should be verified when + /// creating the DTLS context. + final bool verifyPrivateKey; } 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]. diff --git a/pubspec.yaml b/pubspec.yaml index b738ada5..e901c17d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -30,3 +30,13 @@ 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 + dtls2: + git: + url: https://github.com/JKRhb/dtls2 + ref: client-certificates