diff --git a/packages/dart/noports_core/lib/src/common/features.dart b/packages/dart/noports_core/lib/src/common/features.dart index 3631ab4a3..40eac77e0 100644 --- a/packages/dart/noports_core/lib/src/common/features.dart +++ b/packages/dart/noports_core/lib/src/common/features.dart @@ -1,5 +1,9 @@ /// Features which can be supported by the NoPorts Daemon enum DaemonFeatures { + /// daemon will accept public keys sent by clients (i.e. daemon has been + /// started with the `--sshpublickey` or `-s` flag) + acceptsPublicKeys, + /// authenticate when connecting to the Socket Rendezvous (sr) srAuth, diff --git a/packages/dart/noports_core/lib/src/sshnp/models/sshnp_arg.dart b/packages/dart/noports_core/lib/src/sshnp/models/sshnp_arg.dart index acf0519a9..6e50cc96b 100644 --- a/packages/dart/noports_core/lib/src/sshnp/models/sshnp_arg.dart +++ b/packages/dart/noports_core/lib/src/sshnp/models/sshnp_arg.dart @@ -352,6 +352,7 @@ class SshnpArg { ); static const authenticateClientToRvdArg = SshnpArg( name: 'authenticate-client-to-rvd', + abbr: 'a', help: 'When false, client will not authenticate itself to rvd', defaultsTo: DefaultArgs.authenticateClientToRvd, format: ArgFormat.flag, @@ -360,6 +361,7 @@ class SshnpArg { ); static const authenticateDeviceToRvdArg = SshnpArg( name: 'authenticate-device-to-rvd', + abbr: 'A', help: 'When false, device will not authenticate to the socket rendezvous', defaultsTo: DefaultArgs.authenticateDeviceToRvd, format: ArgFormat.flag, @@ -368,6 +370,7 @@ class SshnpArg { ); static const encryptRvdTrafficArg = SshnpArg( name: 'encrypt-rvd-traffic', + abbr: 'E', help: 'When true, traffic via the socket rendezvous is encrypted,' ' in addition to whatever encryption the traffic already has' ' (e.g. an ssh session)', @@ -378,6 +381,7 @@ class SshnpArg { ); static const discoverDaemonFeaturesArg = SshnpArg( name: 'discover-daemon-features', + abbr: 'F', help: 'When this flag is set, this client starts by pinging the daemon to' ' discover what features it supports, and exits if this client has ' ' requested use of a feature which the daemon does not support.' diff --git a/packages/dart/noports_core/lib/src/sshnp/util/sshnpd_channel/sshnpd_channel.dart b/packages/dart/noports_core/lib/src/sshnp/util/sshnpd_channel/sshnpd_channel.dart index b28f71652..f75eba87e 100644 --- a/packages/dart/noports_core/lib/src/sshnp/util/sshnpd_channel/sshnpd_channel.dart +++ b/packages/dart/noports_core/lib/src/sshnp/util/sshnpd_channel/sshnpd_channel.dart @@ -86,9 +86,8 @@ abstract class SshnpdChannel with AsyncInitialization, AtClientBindings { @protected Future handleSshnpdPayload(AtNotification notification); - /// Wait until we've received an acknowledgement from the daemon. - /// Returns true if the daemon acknowledged our request. - /// Returns false if a timeout occurred. + /// Wait until we've received an acknowledgement from the daemon, or + /// have timed out while waiting. Future waitForDaemonResponse({int maxWaitMillis = 15000}) async { // Timer to timeout after 10 Secs or after the Ack of connected/Errors for (int counter = 1; counter <= 100; counter++) { diff --git a/packages/dart/noports_core/lib/src/sshnpd/sshnpd_impl.dart b/packages/dart/noports_core/lib/src/sshnpd/sshnpd_impl.dart index e1908df29..55a0ed412 100644 --- a/packages/dart/noports_core/lib/src/sshnpd/sshnpd_impl.dart +++ b/packages/dart/noports_core/lib/src/sshnpd/sshnpd_impl.dart @@ -309,6 +309,7 @@ class SshnpdImpl implements Sshnpd { 'supportedFeatures': { DaemonFeatures.srAuth.name: true, DaemonFeatures.srE2ee.name: true, + DaemonFeatures.acceptsPublicKeys.name: addSshPublicKeys, }, }; unawaited( diff --git a/packages/dart/noports_core/lib/src/sshrvd/signature_verifying_socket_authenticator.dart b/packages/dart/noports_core/lib/src/sshrvd/signature_verifying_socket_authenticator.dart index ec3616fb7..0f9c2e6c0 100644 --- a/packages/dart/noports_core/lib/src/sshrvd/signature_verifying_socket_authenticator.dart +++ b/packages/dart/noports_core/lib/src/sshrvd/signature_verifying_socket_authenticator.dart @@ -49,6 +49,19 @@ class SignatureAuthVerifier { return atChops.verify(input); } + /// We expect the authenticating client to send a JSON message with + /// this structure: + /// ```json + /// { + /// "signature":"<signature>", + /// "hashingAlgo":"<algo>", + /// "signingAlgo":"<algo>", + /// "payload":<the data which was signed> + /// } + /// ``` + /// The signature is verified against [dataToVerify] and, although not + /// strictly necessary, the rvdNonce is also checked in what the client + /// send in the payload Future<(bool, Stream?)> authenticate(Socket socket) async { Completer<(bool, Stream?)> completer = Completer(); bool authenticated = false; @@ -61,13 +74,6 @@ class SignatureAuthVerifier { try { final message = String.fromCharCodes(data); logger.info('SignatureAuthVerifier $tag received data: $message'); - // Expected message to be the JSON format with the below structure: - // { - // "signature":"", - // "hashingAlgo":"", - // "signingAlgo":"", - // "payload":{} - // } var envelope = jsonDecode(message); final hashingAlgo =