summaryrefslogtreecommitdiffhomepage
path: root/control
diff options
context:
space:
mode:
Diffstat (limited to 'control')
-rw-r--r--control/controlhttp/client.go5
-rw-r--r--control/controlhttp/server.go12
2 files changed, 17 insertions, 0 deletions
diff --git a/control/controlhttp/client.go b/control/controlhttp/client.go
index c9db75025..62bdce556 100644
--- a/control/controlhttp/client.go
+++ b/control/controlhttp/client.go
@@ -50,6 +50,10 @@ const (
// payload, to save an RTT.
handshakeHeaderName = "X-Tailscale-Handshake"
+ // serverPubHeaderName is the HTTP request header that
+ // says the expected public key of the control plane.
+ serverPubHeaderName = "X-Tailscale-Control-Public"
+
// serverUpgradePath is where the server-side HTTP handler to
// to do the protocol switch is located.
serverUpgradePath = "/ts2021"
@@ -194,6 +198,7 @@ func (a *dialParams) tryURL(u *url.URL, init []byte) (net.Conn, error) {
"Upgrade": []string{upgradeHeaderValue},
"Connection": []string{"upgrade"},
handshakeHeaderName: []string{base64.StdEncoding.EncodeToString(init)},
+ serverPubHeaderName: []string{a.controlKey.String()},
},
}
req = req.WithContext(ctx)
diff --git a/control/controlhttp/server.go b/control/controlhttp/server.go
index 92bd9ec9b..a446a0ebc 100644
--- a/control/controlhttp/server.go
+++ b/control/controlhttp/server.go
@@ -44,6 +44,18 @@ func AcceptHTTP(ctx context.Context, w http.ResponseWriter, r *http.Request, pri
return nil, fmt.Errorf("decoding base64 handshake header: %v", err)
}
+ if wantPub := r.Header.Get(serverPubHeaderName); wantPub != "" {
+ // If the client declared the public key they expect to speak to,
+ // check it.
+ // TODO: replace the 'private' parameter with a func/interface
+ // that looks up the private key as a function of the public key
+ // to see if we have a currently in-rotation key that's valid.
+ if private.Public().String() != wantPub {
+ http.Error(w, "requested server key unavailable", http.StatusServiceUnavailable)
+ return nil, errors.New("client requested unavailble server key")
+ }
+ }
+
hijacker, ok := w.(http.Hijacker)
if !ok {
http.Error(w, "make request over HTTP/1", http.StatusBadRequest)