6fede806
deps: x/crypto v0.56.0, and the gate names the option it accepts
a73x 2026-09-05 17:43
Commit message
go.mod
| Old | New | ||
|---|---|---|---|
| @@ -13,7 +13,7 @@ require ( | |||
| 13 | github.com/quic-go/quic-go v0.49.1 | 13 | github.com/quic-go/quic-go v0.49.1 |
| 14 | github.com/stretchr/testify v1.11.1 | 14 | github.com/stretchr/testify v1.11.1 |
| 15 | github.com/yuin/goldmark v1.8.4 | 15 | github.com/yuin/goldmark v1.8.4 |
| 16 | golang.org/x/crypto v0.55.0 | 16 | golang.org/x/crypto v0.56.0 |
| 17 | golang.org/x/net v0.57.0 | 17 | golang.org/x/net v0.57.0 |
| 18 | golang.org/x/oauth2 v0.36.0 | 18 | golang.org/x/oauth2 v0.36.0 |
| 19 | golang.org/x/sync v0.22.0 | 19 | golang.org/x/sync v0.22.0 |
go.sum
| Old | New | ||
|---|---|---|---|
| @@ -95,8 +95,8 @@ github.com/yuin/goldmark v1.8.4 h1:oat/nd3U6NeQqFEL3xpEJq7d7c86NI+DbSNGAs4xnjA= | |||
| 95 | github.com/yuin/goldmark v1.8.4/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= | 95 | github.com/yuin/goldmark v1.8.4/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= |
| 96 | go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= | 96 | go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= |
| 97 | go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= | 97 | go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= |
| 98 | golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M= | 98 | golang.org/x/crypto v0.56.0 h1:GUh5Ii4J5jtcseSMiRqr1jXCNHoxjeV9Fmekc2oLy6Y= |
| 99 | golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis= | 99 | golang.org/x/crypto v0.56.0/go.mod h1:OMW5y6CY9l38uPLmxU6l6pwcXp1obtLo3e6gT7gQR2I= |
| 100 | golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= | 100 | golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= |
| 101 | golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= | 101 | golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= |
| 102 | golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= | 102 | golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= |
internal/server/sshgate/gate.go
| Old | New | ||
|---|---|---|---|
| @@ -125,6 +125,21 @@ const ( | |||
| 125 | func New(hostKey ssh.Signer, userCAs UserCALookup, resolve Resolver, authorize Authorizer, dial Dialer, isRevoked Revoker, audit Audit) *Gate { | 125 | func New(hostKey ssh.Signer, userCAs UserCALookup, resolve Resolver, authorize Authorizer, dial Dialer, isRevoked Revoker, audit Audit) *Gate { |
| 126 | checker := &ssh.CertChecker{ | 126 | checker := &ssh.CertChecker{ |
| 127 | IsUserAuthority: func(auth ssh.PublicKey) bool { _, ok := userCAs(auth); return ok }, | 127 | IsUserAuthority: func(auth ssh.PublicKey) bool { _, ok := userCAs(auth); return ok }, |
| 128 | // `source-address` is the ONE critical option this gate accepts, and it | ||
| 129 | // has to be named here because we call CheckCert directly rather than | ||
| 130 | // going through CertChecker.Authenticate (see the principal argument | ||
| 131 | // below for why). Authenticate is what exempts source-address on a | ||
| 132 | // caller's behalf — it clones the checker and appends this same | ||
| 133 | // constant — so a direct CheckCert caller that names nothing rejects | ||
| 134 | // every source-address cert as an unsupported option. | ||
| 135 | // | ||
| 136 | // Naming it does NOT enforce it. CheckCert only decides whether an | ||
| 137 | // option is understood; the enforcement happens in x/crypto's | ||
| 138 | // serverAuthenticate, against the address the connection actually came | ||
| 139 | // from, read from the Permissions returned below. Listing exactly this | ||
| 140 | // one keeps the gate's promise intact: an option it cannot honour is | ||
| 141 | // still a promise it must not accept (TestGateRejectsUnknownCriticalOption). | ||
| 142 | SupportedCriticalOptions: []string{"source-address"}, | ||
| 128 | } | 143 | } |
| 129 | // CheckCert consults IsRevoked during validation: a true result fails the | 144 | // CheckCert consults IsRevoked during validation: a true result fails the |
| 130 | // cert authentication outright, so a revoked cert cannot open the tunnel. | 145 | // cert authentication outright, so a revoked cert cannot open the tunnel. |
| @@ -181,13 +196,14 @@ func New(hostKey ssh.Signer, userCAs UserCALookup, resolve Resolver, authorize A | |||
| 181 | } | 196 | } |
| 182 | return &ssh.Permissions{ | 197 | return &ssh.Permissions{ |
| 183 | // The cert's own restrictions, carried back so the server layer | 198 | // The cert's own restrictions, carried back so the server layer |
| 184 | // applies them. CheckCert above skips `source-address` on purpose; | 199 | // applies them. CheckCert above ACCEPTS `source-address` without |
| 185 | // x/crypto's serverAuthenticate is what checks it, against the | 200 | // checking it (see SupportedCriticalOptions where the checker is |
| 186 | // address the connection actually came from, and it reads it from | 201 | // built); x/crypto's serverAuthenticate is what checks it, |
| 187 | // the permissions returned here. The plane runs on the host | 202 | // against the address the connection actually came from, and it |
| 188 | // network, so that address is the client's, not a proxy's. Every | 203 | // reads it from the permissions returned here. The plane runs on |
| 189 | // other critical option is still refused by CheckCert, which has | 204 | // the host network, so that address is the client's, not a |
| 190 | // no SupportedCriticalOptions set. | 205 | // proxy's. Every other critical option is still refused by |
| 206 | // CheckCert, which supports only that one. | ||
| 191 | CriticalOptions: cert.CriticalOptions, | 207 | CriticalOptions: cert.CriticalOptions, |
| 192 | Extensions: map[string]string{ | 208 | Extensions: map[string]string{ |
| 193 | // The tenant of the CA that signed this cert, resolved from the | 209 | // The tenant of the CA that signed this cert, resolved from the |