From 4da559d7cc9e759a6f2d714ff5aeb6594074e5ff Mon Sep 17 00:00:00 2001 From: Adrian Dewhurst Date: Fri, 17 Sep 2021 13:17:57 -0400 Subject: [PATCH] control/controlclient: update machine certificate signature version This iterates on the original signature format. Signed-off-by: Adrian Dewhurst --- control/controlclient/sign.go | 26 ++++++++++++++++++------- control/controlclient/sign_supported.go | 7 +++++-- tailcfg/tailcfg.go | 12 +++++++++++- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/control/controlclient/sign.go b/control/controlclient/sign.go index 846d562dd..c57f075d5 100644 --- a/control/controlclient/sign.go +++ b/control/controlclient/sign.go @@ -10,22 +10,34 @@ "fmt" "time" + "tailscale.com/tailcfg" "tailscale.com/types/key" ) var ( - errNoCertStore = errors.New("no certificate store") - errCertificateNotConfigured = errors.New("no certificate subject configured") + errNoCertStore = errors.New("no certificate store") + errCertificateNotConfigured = errors.New("no certificate subject configured") + errUnsupportedSignatureVersion = errors.New("unsupported signature version") ) // HashRegisterRequest generates the hash required sign or verify a -// tailcfg.RegisterRequest with tailcfg.SignatureV1. -func HashRegisterRequest(ts time.Time, serverURL string, deviceCert []byte, serverPubKey, machinePubKey key.MachinePublic) []byte { +// tailcfg.RegisterRequest. +func HashRegisterRequest( + version tailcfg.SignatureType, ts time.Time, serverURL string, deviceCert []byte, + serverPubKey, machinePubKey key.MachinePublic) ([]byte, error) { h := crypto.SHA256.New() // hash.Hash.Write never returns an error, so we don't check for one here. - fmt.Fprintf(h, "%s%s%s%s%s", - ts.UTC().Format(time.RFC3339), serverURL, deviceCert, serverPubKey, machinePubKey) + switch version { + case tailcfg.SignatureV1: + fmt.Fprintf(h, "%s%s%s%s%s", + ts.UTC().Format(time.RFC3339), serverURL, deviceCert, serverPubKey.ShortString(), machinePubKey.ShortString()) + case tailcfg.SignatureV2: + fmt.Fprintf(h, "%s%s%s%s%s", + ts.UTC().Format(time.RFC3339), serverURL, deviceCert, serverPubKey, machinePubKey) + default: + return nil, errUnsupportedSignatureVersion + } - return h.Sum(nil) + return h.Sum(nil), nil } diff --git a/control/controlclient/sign_supported.go b/control/controlclient/sign_supported.go index 7a258ae10..63f362a57 100644 --- a/control/controlclient/sign_supported.go +++ b/control/controlclient/sign_supported.go @@ -167,7 +167,11 @@ func signRegisterRequest(req *tailcfg.RegisterRequest, serverURL string, serverP req.DeviceCert = append(req.DeviceCert, c.Raw...) } - h := HashRegisterRequest(req.Timestamp.UTC(), serverURL, req.DeviceCert, serverPubKey, machinePubKey) + req.SignatureType = tailcfg.SignatureV2 + h, err := HashRegisterRequest(req.SignatureType, req.Timestamp.UTC(), serverURL, req.DeviceCert, serverPubKey, machinePubKey) + if err != nil { + return fmt.Errorf("hash: %w", err) + } req.Signature, err = signer.Sign(nil, h, &rsa.PSSOptions{ SaltLength: rsa.PSSSaltLengthEqualsHash, @@ -176,7 +180,6 @@ func signRegisterRequest(req *tailcfg.RegisterRequest, serverURL string, serverP if err != nil { return fmt.Errorf("sign: %w", err) } - req.SignatureType = tailcfg.SignatureV1 return nil } diff --git a/tailcfg/tailcfg.go b/tailcfg/tailcfg.go index 1df4cf388..bef39bb2b 100644 --- a/tailcfg/tailcfg.go +++ b/tailcfg/tailcfg.go @@ -558,10 +558,16 @@ func (h *Hostinfo) Equal(h2 *Hostinfo) bool { // be considered an error if seen. SignatureUnknown // SignatureV1 is computed as RSA-PSS-Sign(privateKeyForDeviceCert, + // SHA256(Timestamp || ServerIdentity || DeviceCert || ServerShortPubKey || + // MachineShortPubKey)). The PSS salt length is equal to hash length + // (rsa.PSSSaltLengthEqualsHash). Device cert is required. + // Deprecated: uses old key serialization format. + SignatureV1 + // SignatureV2 is computed as RSA-PSS-Sign(privateKeyForDeviceCert, // SHA256(Timestamp || ServerIdentity || DeviceCert || ServerPubKey || // MachinePubKey)). The PSS salt length is equal to hash length // (rsa.PSSSaltLengthEqualsHash). Device cert is required. - SignatureV1 + SignatureV2 ) func (st SignatureType) MarshalText() ([]byte, error) { @@ -574,6 +580,8 @@ func (st *SignatureType) UnmarshalText(b []byte) error { *st = SignatureNone case "signature-v1": *st = SignatureV1 + case "signature-v2": + *st = SignatureV2 default: var val int if _, err := fmt.Sscanf(string(b), "signature-unknown(%d)", &val); err != nil { @@ -593,6 +601,8 @@ func (st SignatureType) String() string { return "signature-unknown" case SignatureV1: return "signature-v1" + case SignatureV2: + return "signature-v2" default: return fmt.Sprintf("signature-unknown(%d)", int(st)) }