1
1
package sshutil
2
2
3
3
import (
4
+ "bytes"
4
5
"errors"
5
6
"fmt"
6
7
"io/fs"
7
8
"os"
8
9
"os/exec"
9
10
"path/filepath"
11
+ "regexp"
10
12
"strings"
13
+ "sync"
11
14
15
+ "github.com/coreos/go-semver/semver"
12
16
"github.com/lima-vm/lima/pkg/lockutil"
13
17
"github.com/lima-vm/lima/pkg/osutil"
14
18
"github.com/lima-vm/lima/pkg/store/dirnames"
@@ -102,6 +106,15 @@ func DefaultPubKeys(loadDotSSH bool) ([]PubKey, error) {
102
106
return res , nil
103
107
}
104
108
109
+ var sshInfo struct {
110
+ sync.Once
111
+ // aesAccelerated is set to true when AES acceleration is available.
112
+ // Available on almost all modern Intel/AMD processors.
113
+ aesAccelerated bool
114
+ // openSSHVersion is set to the version of OpenSSH, or semver.New("0.0.0") if the version cannot be determined.
115
+ openSSHVersion semver.Version
116
+ }
117
+
105
118
func CommonArgs (useDotSSH bool ) ([]string , error ) {
106
119
configDir , err := dirnames .LimaConfigDir ()
107
120
if err != nil {
@@ -159,16 +172,24 @@ func CommonArgs(useDotSSH bool) ([]string, error) {
159
172
"-F" , "/dev/null" ,
160
173
)
161
174
162
- // By default, `ssh` choose chacha20-poly1305@openssh.com, even when AES accelerator is available.
163
- // (OpenSSH_8.1p1, macOS 11.6, MacBookPro 2020, Core i7-1068NG7)
164
- //
165
- // We prioritize AES algorithms when AES accelerator is available.
166
- if aesAccelerated {
167
- logrus .Debugf ("AES accelerator seems available, prioritizing aes128-gcm@openssh.com and aes256-gcm@openssh.com" )
168
- args = append (args , "-o" , "Ciphers=^aes128-gcm@openssh.com,aes256-gcm@openssh.com" )
169
- } else {
170
- logrus .Debugf ("AES accelerator does not seem available, prioritizing chacha20-poly1305@openssh.com" )
171
- args = append (args , "-o" , "Ciphers=^chacha20-poly1305@openssh.com" )
175
+ sshInfo .Do (func () {
176
+ sshInfo .aesAccelerated = detectAESAcceleration ()
177
+ sshInfo .openSSHVersion = detectOpenSSHVersion ()
178
+ })
179
+
180
+ // Only OpenSSH version 8.0 and later support adding ciphers to the front of the default set
181
+ if ! sshInfo .openSSHVersion .LessThan (* semver .New ("8.0.0" )) {
182
+ // By default, `ssh` choose chacha20-poly1305@openssh.com, even when AES accelerator is available.
183
+ // (OpenSSH_8.1p1, macOS 11.6, MacBookPro 2020, Core i7-1068NG7)
184
+ //
185
+ // We prioritize AES algorithms when AES accelerator is available.
186
+ if sshInfo .aesAccelerated {
187
+ logrus .Debugf ("AES accelerator seems available, prioritizing aes128-gcm@openssh.com and aes256-gcm@openssh.com" )
188
+ args = append (args , "-o" , "Ciphers=^aes128-gcm@openssh.com,aes256-gcm@openssh.com" )
189
+ } else {
190
+ logrus .Debugf ("AES accelerator does not seem available, prioritizing chacha20-poly1305@openssh.com" )
191
+ args = append (args , "-o" , "Ciphers=^chacha20-poly1305@openssh.com" )
192
+ }
172
193
}
173
194
return args , nil
174
195
}
@@ -195,7 +216,25 @@ func SSHArgs(instDir string, useDotSSH bool) ([]string, error) {
195
216
return args , nil
196
217
}
197
218
198
- // aesAccelerated is set to true when AES acceleration is available.
199
- //
200
- // Available on almost all modern Intel/AMD processors.
201
- var aesAccelerated = detectAESAcceleration ()
219
+ func detectOpenSSHVersion () semver.Version {
220
+ var (
221
+ v semver.Version
222
+ stderr bytes.Buffer
223
+ )
224
+ cmd := exec .Command ("ssh" , "-V" )
225
+ cmd .Stderr = & stderr
226
+ if err := cmd .Run (); err != nil {
227
+ logrus .Warnf ("failed to run %v: stderr=%q" , cmd .Args , stderr .String ())
228
+ } else {
229
+ regex := regexp .MustCompile (`^OpenSSH_(\d+\.\d+)(?:p(\d+))?\b` )
230
+ matches := regex .FindSubmatch (stderr .Bytes ())
231
+ if len (matches ) == 3 {
232
+ if len (matches [2 ]) == 0 {
233
+ matches [2 ] = []byte ("0" )
234
+ }
235
+ v = * semver .New (fmt .Sprintf ("%s.%s" , matches [1 ], matches [2 ]))
236
+ }
237
+ }
238
+ logrus .Debugf ("OpenSSH version %s detected" , v )
239
+ return v
240
+ }
0 commit comments