Skip to content

[rest]: Fix RESTCONF basic auth — rsa-sha2 host keys and FIPS-safe SSH KEX#164

Open
Griffin-micas wants to merge 1 commit into
sonic-net:masterfrom
Griffin-micas:bugfix-restconf-basic-auth-hostkey-kex
Open

[rest]: Fix RESTCONF basic auth — rsa-sha2 host keys and FIPS-safe SSH KEX#164
Griffin-micas wants to merge 1 commit into
sonic-net:masterfrom
Griffin-micas:bugfix-restconf-basic-auth-hostkey-kex

Conversation

@Griffin-micas

@Griffin-micas Griffin-micas commented Jul 8, 2026

Copy link
Copy Markdown

Fixes sonic-net/sonic-buildimage#28142
RESTCONF basic auth (which dials the local sshd) is broken two ways: the pinned 2020 x/crypto has no rsa-sha2-256/512 host-key algorithms so it never matches OpenSSH ≥8.8, and once bumped the default curve25519 key exchange panics under FIPS (golang- fips rejects X25519), crashing the process. Bump x/crypto to v0.24.0 and pin the auth SSH client to FIPS-approved ECDH-P256/AES- GCM.

Why I did it

RESTCONF username/password (HTTP basic) authentication is broken. Basic auth is implemented by dialing the local sshd (rest/server/pamAuth.go does ssh.Dial 127.0.0.1:22 because the container has no access to the host's /etc/passwd//etc/shadow). Two problems stack on top of each other:

1. No common host-key algorithm (all images with modern OpenSSH).
The pinned golang.org/x/crypto (2020) advertises only ssh-rsa/ssh-ed25519/ecdsa-* host-key algorithms. OpenSSH >= 8.8 no longer offers ssh-rsa (SHA-1) and, with only an RSA host key present, offers rsa-sha2-512/rsa-sha2-256. There is no intersection, so the SSH handshake fails and every login returns 401, regardless of credentials:

pamAuth.go Failed to authenticate; ssh: handshake failed:
  ssh: no common algorithm for host key;
  client offered: [... ecdsa-sha2-nistp256 ssh-rsa ssh-ed25519],
  server offered: [rsa-sha2-512 rsa-sha2-256]

This is not FIPS-specific — it affects any image whose sshd is OpenSSH >= 8.8.

2. Key exchange panics under FIPS (sonic_fips=1).
Once the host-key issue is fixed and the handshake proceeds, x/crypto/ssh defaults to curve25519-sha256 for key exchange. Under FIPS the golang-fips crypto layer rejects X25519 (the same policy that makes rest_server's own TLS refuse the X25519 curve), so the exchange panics inside the ssh handshake goroutine, which net/http cannot recover — crashing the whole rest_server process:

panic: curve25519: internal error: scalarBaseMult was not 32 bytes
  golang.org/x/crypto/ssh/handshake.go
  created by golang.org/x/crypto/ssh.newClientTransport in goroutine 13
...
WARN exited: rest-server (exit status 2; not expected)   # supervisord respawns; client sees "unexpected eof"

Problem 2 is exposed by fixing problem 1, so both must ship together. golang-fips crashing (rather than returning an error) on an unsupported KEX is arguably an upstream bug — tracked in #; this PR avoids it by constraining the exchange.

How I did it

Two coupled changes:

a. Bump golang.org/x/crypto to v0.24.0 (go.mod/go.sum), which supports the rsa-sha2-256/rsa-sha2-512 host-key algorithms. v0.24.0 is deliberately chosen to match the existing SONiC-wide pin (sonic-gnmi already forces x/crypto => v0.24.0 via a replace directive), keeping the go-directive floor low for backport compatibility. Newer versions add nothing for this fix (rsa-sha2 support has been present since ~2021). Note: CVE-2024-45337 (x/crypto/ssh, fixed v0.31.0) concerns server-side ServerConfig.PublicKeyCallback misuse; this code is a client using password auth and does not use PublicKeyCallback, so it is not affected.

b. Pin FIPS-approved KEX/cipher for the auth ssh client (rest/server/pamAuth.go):

        config := &ssh.ClientConfig{
                User:            username,
                Auth:            []ssh.AuthMethod{ssh.Password(passwd)},
                HostKeyCallback: ssh.InsecureIgnoreHostKey(),
                Config: ssh.Config{
                        KeyExchanges: []string{"ecdh-sha2-nistp256", "ecdh-sha2-nistp384", "ecdh-sha2-nistp521"},
                        Ciphers:      []string{"aes128-gcm@openssh.com", "aes256-gcm@openssh.com"},
                },
        }

This is a loopback connection to the local sshd, which always offers these NIST algorithms (P-256 ECDH is FIPS-mandatory), so restricting to them is safe on both FIPS and non-FIPS images and avoids the X25519 KEX entirely. AES-GCM is an AEAD, so no separate (potentially unsupported) MAC is negotiated; the RSA-SHA2 host key uses RSA verification, which symcrypt supports.

How to verify it

On a sonic_fips=1 image, with a correct admin password:

curl -k --noproxy '*' -u admin:<correct-pw> \
  "https://<dut>/restconf/data/openconfig-interfaces:interfaces/interface=Ethernet1" \
  -H "accept: application/yang-data+json"
  • Before: curl: (56) SSL_read: unexpected eof and docker logs mgmt-framework shows exited: rest-server (exit status 2).
  • After: returns 200 with the interface data. A wrong password returns a clean 401, and the process no longer crashes (no exit status 2 in docker logs).

Protocol-level confirmation that the pinned algorithms handshake against the local FIPS sshd:

ssh -o KexAlgorithms=ecdh-sha2-nistp256 -o Ciphers=aes128-gcm@openssh.com admin@127.0.0.1 exit
# debug1: kex: algorithm: ecdh-sha2-nistp256
# debug1: kex: host key algorithm: rsa-sha2-512
# debug1: kex: cipher: aes128-gcm@openssh.com   -> reaches password auth (no X25519 panic)

…H KEX

RESTCONF basic auth (which dials the local sshd) is broken two ways: the pinned 2020 x/crypto has no rsa-sha2-256/512 host-key
algorithms so it never matches OpenSSH ≥8.8, and once bumped the default curve25519 key exchange panics under FIPS (golang-
fips rejects X25519), crashing the process. Bump x/crypto to v0.24.0 and pin the auth SSH client to FIPS-approved ECDH-P256/AES-
GCM.

Signed-off-by: Griffin Gao <griffin@micasnetworks.com>
@mssonicbld

Copy link
Copy Markdown

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@mssonicbld

Copy link
Copy Markdown

Hi, there are workflow run(s) waiting for approval, you may be first-time contributor. I will notify maintainers to help approve once PR is approved. Thanks!

---Powered by SONiC BuildBot

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants