Skip to content

Commit

Permalink
Merge pull request #1090 from atsign-foundation/no-double-ssh-when-so…
Browse files Browse the repository at this point in the history
…ckets-encrypted
  • Loading branch information
gkc authored Jun 5, 2024
2 parents ada9b30 + abb0422 commit b17e64a
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 71 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class SshnpDartPureImpl extends SshnpCore
}

SSHClient? tunnelSshClient;
SSHSocket? _sshSocketForUserSession;

@override
Future<void> dispose() async {
Expand Down Expand Up @@ -97,45 +98,51 @@ class SshnpDartPureImpl extends SshnpCore
} else {
sendProgress('Received response from the device daemon');
}

if (sshnpdChannel.ephemeralPrivateKey == null) {
if (sshnpdChannel.ephemeralPrivateKey == null &&
!params.encryptRvdTraffic) {
throw SshnpError(
'Expected an ephemeral private key from device daemon, but it was not set',
);
}

/// Load the ephemeral private key into a key pair
AtSshKeyPair ephemeralKeyPair = AtSshKeyPair.fromPem(
sshnpdChannel.ephemeralPrivateKey!,
identifier: 'ephemeral_$sessionId',
);

/// Add the key pair to the key utility
await keyUtil.addKeyPair(keyPair: ephemeralKeyPair);

/// Start srv
sendProgress('Creating connection to socket rendezvous');
SSHSocket? sshSocket = await srvdChannel.runSrv(
SSHSocket? temp = await srvdChannel.runSrv(
sessionAESKeyString: sshnpdChannel.sessionAESKeyString,
sessionIVString: sshnpdChannel.sessionIVString,
multi: false,
detached: false,
);

try {
/// Start the initial tunnel
sendProgress('Starting tunnel session');
tunnelSshClient = await startInitialTunnelSession(
ephemeralKeyPairIdentifier: ephemeralKeyPair.identifier,
sshSocket: sshSocket,
// If we're not encrypting traffic on the sockets, then we create an extra
// ssh session in order to encrypt the user's "real" ssh session.
if (params.encryptRvdTraffic == false) {
/// Load the ephemeral private key into a key pair
AtSshKeyPair ephemeralKeyPair = AtSshKeyPair.fromPem(
sshnpdChannel.ephemeralPrivateKey!,
identifier: 'ephemeral_$sessionId',
);
} finally {
/// Remove the key pair from the key utility

/// Add the key pair to the key utility
await keyUtil.addKeyPair(keyPair: ephemeralKeyPair);

try {
await keyUtil.deleteKeyPair(identifier: ephemeralKeyPair.identifier);
} catch (e) {
logger.shout('Failed to delete ephemeral keyPair: $e');
/// Start the initial tunnel
sendProgress('Starting tunnel session');
tunnelSshClient = await startInitialTunnelSession(
ephemeralKeyPairIdentifier: ephemeralKeyPair.identifier,
sshSocket: temp,
);
} finally {
/// Remove the key pair from the key utility
try {
await keyUtil.deleteKeyPair(identifier: ephemeralKeyPair.identifier);
} catch (e) {
logger.shout('Failed to delete ephemeral keyPair: $e');
}
}
} else {
_sshSocketForUserSession = temp;
}

/// Ensure that we clean up after ourselves
Expand All @@ -158,14 +165,9 @@ class SshnpDartPureImpl extends SshnpCore

@override
Future<SshnpRemoteProcess> runShell() async {
if (tunnelSshClient == null) {
throw StateError(
'Cannot execute runShell, tunnel has not yet been created');
}

sendProgress('Starting user session');
SSHClient userSession =
await startUserSession(tunnelSession: tunnelSshClient!);
await startUserSession(sshSocket: _sshSocketForUserSession);

sendProgress('Starting remote shell');
SSHSession shell = await userSession.shell();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,16 +90,25 @@ class SshnpOpensshLocalImpl extends SshnpCore
sendProgress('Received response from the device daemon');
}

if (sshnpdChannel.ephemeralPrivateKey == null) {
if (sshnpdChannel.ephemeralPrivateKey == null &&
!params.encryptRvdTraffic) {
throw SshnpError(
'Expected an ephemeral private key from sshnpd, but it was not set',
);
}

/// Find a port to use
final server = await ServerSocket.bind(InternetAddress.anyIPv4, 0);
int localRvPort = server.port;
await server.close();
final int localRvPort;
// If we're not encrypting traffic on the sockets, then we create an extra
// ssh session in order to encrypt the user's "real" ssh session. And we
// need to grab an unused local port.
if (params.encryptRvdTraffic == false) {
/// Find a port to use for the tunnel ssh session
final server = await ServerSocket.bind(InternetAddress.anyIPv4, 0);
localRvPort = server.port;
await server.close();
} else {
localRvPort = localPort;
}

/// Start srv
sendProgress('Creating connection to socket rendezvous');
Expand All @@ -111,30 +120,35 @@ class SshnpOpensshLocalImpl extends SshnpCore
detached: true,
);

/// Load the ephemeral private key into a key pair
AtSshKeyPair ephemeralKeyPair = AtSshKeyPair.fromPem(
sshnpdChannel.ephemeralPrivateKey!,
identifier: 'ephemeral_$sessionId',
directory: keyUtil.sshnpHomeDirectory,
);

/// Add the key pair to the key utility
await keyUtil.addKeyPair(keyPair: ephemeralKeyPair);

Process? bean;
try {
/// Start the initial tunnel
sendProgress('Starting tunnel session');
bean = await startInitialTunnelSession(
ephemeralKeyPairIdentifier: ephemeralKeyPair.identifier,
localRvPort: localRvPort,

// If we're not encrypting traffic on the sockets, then we create an extra
// ssh session in order to encrypt the user's "real" ssh session.
if (params.encryptRvdTraffic == false) {
/// Load the ephemeral private key into a key pair
AtSshKeyPair ephemeralKeyPair = AtSshKeyPair.fromPem(
sshnpdChannel.ephemeralPrivateKey!,
identifier: 'ephemeral_$sessionId',
directory: keyUtil.sshnpHomeDirectory,
);
} finally {
/// Remove the key pair from the key utility.

/// Add the key pair to the key utility
await keyUtil.addKeyPair(keyPair: ephemeralKeyPair);

try {
await keyUtil.deleteKeyPair(identifier: ephemeralKeyPair.identifier);
} catch (e) {
logger.shout('Failed to delete ephemeral keyPair: $e');
/// Start the initial tunnel
sendProgress('Starting tunnel session');
bean = await startInitialTunnelSession(
ephemeralKeyPairIdentifier: ephemeralKeyPair.identifier,
localRvPort: localRvPort,
);
} finally {
/// Remove the key pair from the key utility.
try {
await keyUtil.deleteKeyPair(identifier: ephemeralKeyPair.identifier);
} catch (e) {
logger.shout('Failed to delete ephemeral keyPair: $e');
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,7 @@ mixin DartSshSessionHandler on SshnpCore
}

@override
Future<SSHClient> startUserSession({
required SSHClient tunnelSession,
}) async {
Future<SSHClient> startUserSession({SSHSocket? sshSocket}) async {
if (identityKeyPair == null) {
throw SshnpError('Identity Key pair is mandatory with the dart client.');
}
Expand All @@ -101,13 +99,24 @@ mixin DartSshSessionHandler on SshnpCore
logger
.info('Starting user ssh session as $username to localhost:$localPort');

SSHClient userSshClient;
SshClientHelper helper = SshClientHelper(logger);
SSHClient userSshClient = await helper.createDirectSshClient(
host: 'localhost',
port: localPort,
username: username,
keyPair: identityKeyPair!,
);
if (sshSocket == null) {
userSshClient = await helper.createDirectSshClient(
host: 'localhost',
port: localPort,
username: username,
keyPair: identityKeyPair!,
);
} else {
userSshClient = await helper.createSshClientWithSshSocket(
sshSocket: sshSocket,
host: 'localhost',
port: localPort,
username: username,
keyPair: identityKeyPair!,
);
}

if (!params.addForwardsToTunnel) {
var optionsSplitBySpace = params.localSshOptions.join(' ').split(' ');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,7 @@ mixin OpensshSshSessionHandler on SshnpCore
}

@override
Future<Process?> startUserSession({
required Process? tunnelSession,
}) async {
Future<Process?> startUserSession() async {
throw UnimplementedError();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,5 @@ mixin SshSessionHandler<T> {

@protected
@visibleForTesting
Future<T> startUserSession({
required T tunnelSession,
});
Future<T> startUserSession();
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class StubbedSshnp extends SshnpCore
final SrvdChannel _srvdChannel;

@override
Future<Process?> startUserSession({required Process? tunnelSession}) {
Future<Process?> startUserSession() {
throw UnimplementedError();
}

Expand Down
2 changes: 2 additions & 0 deletions tests/e2e_all/scripts/common/apkam_setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ enroll() {
apkamDev=$(getApkamDeviceName "$which" "$commitId")
keysFileName=$(getApkamKeysFile "$atSign" "$apkamApp" "$apkamDev")

rm -f "$keysFileName"

logInfo "Denying any pending enrollment requests for $atSign with apkamAppName $apkamApp and apkamDeviceName $apkamDev"
$authBinary deny -r "$atDirectoryHost" -a "$atSign" --arx "$apkamApp" --drx "$apkamDev" || return $?

Expand Down

0 comments on commit b17e64a

Please sign in to comment.