control/controlclient: update machine certificate signature version

This iterates on the original signature format.

Signed-off-by: Adrian Dewhurst <adrian@tailscale.com>
This commit is contained in:
Adrian Dewhurst 2021-09-17 13:17:57 -04:00 committed by Adrian Dewhurst
parent a722e48cef
commit 4da559d7cc
3 changed files with 35 additions and 10 deletions

View File

@ -10,22 +10,34 @@
"fmt" "fmt"
"time" "time"
"tailscale.com/tailcfg"
"tailscale.com/types/key" "tailscale.com/types/key"
) )
var ( var (
errNoCertStore = errors.New("no certificate store") errNoCertStore = errors.New("no certificate store")
errCertificateNotConfigured = errors.New("no certificate subject configured") errCertificateNotConfigured = errors.New("no certificate subject configured")
errUnsupportedSignatureVersion = errors.New("unsupported signature version")
) )
// HashRegisterRequest generates the hash required sign or verify a // HashRegisterRequest generates the hash required sign or verify a
// tailcfg.RegisterRequest with tailcfg.SignatureV1. // tailcfg.RegisterRequest.
func HashRegisterRequest(ts time.Time, serverURL string, deviceCert []byte, serverPubKey, machinePubKey key.MachinePublic) []byte { func HashRegisterRequest(
version tailcfg.SignatureType, ts time.Time, serverURL string, deviceCert []byte,
serverPubKey, machinePubKey key.MachinePublic) ([]byte, error) {
h := crypto.SHA256.New() h := crypto.SHA256.New()
// hash.Hash.Write never returns an error, so we don't check for one here. // hash.Hash.Write never returns an error, so we don't check for one here.
fmt.Fprintf(h, "%s%s%s%s%s", switch version {
ts.UTC().Format(time.RFC3339), serverURL, deviceCert, serverPubKey, machinePubKey) 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
} }

View File

@ -167,7 +167,11 @@ func signRegisterRequest(req *tailcfg.RegisterRequest, serverURL string, serverP
req.DeviceCert = append(req.DeviceCert, c.Raw...) 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{ req.Signature, err = signer.Sign(nil, h, &rsa.PSSOptions{
SaltLength: rsa.PSSSaltLengthEqualsHash, SaltLength: rsa.PSSSaltLengthEqualsHash,
@ -176,7 +180,6 @@ func signRegisterRequest(req *tailcfg.RegisterRequest, serverURL string, serverP
if err != nil { if err != nil {
return fmt.Errorf("sign: %w", err) return fmt.Errorf("sign: %w", err)
} }
req.SignatureType = tailcfg.SignatureV1
return nil return nil
} }

View File

@ -558,10 +558,16 @@ func (h *Hostinfo) Equal(h2 *Hostinfo) bool {
// be considered an error if seen. // be considered an error if seen.
SignatureUnknown SignatureUnknown
// SignatureV1 is computed as RSA-PSS-Sign(privateKeyForDeviceCert, // 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 || // SHA256(Timestamp || ServerIdentity || DeviceCert || ServerPubKey ||
// MachinePubKey)). The PSS salt length is equal to hash length // MachinePubKey)). The PSS salt length is equal to hash length
// (rsa.PSSSaltLengthEqualsHash). Device cert is required. // (rsa.PSSSaltLengthEqualsHash). Device cert is required.
SignatureV1 SignatureV2
) )
func (st SignatureType) MarshalText() ([]byte, error) { func (st SignatureType) MarshalText() ([]byte, error) {
@ -574,6 +580,8 @@ func (st *SignatureType) UnmarshalText(b []byte) error {
*st = SignatureNone *st = SignatureNone
case "signature-v1": case "signature-v1":
*st = SignatureV1 *st = SignatureV1
case "signature-v2":
*st = SignatureV2
default: default:
var val int var val int
if _, err := fmt.Sscanf(string(b), "signature-unknown(%d)", &val); err != nil { if _, err := fmt.Sscanf(string(b), "signature-unknown(%d)", &val); err != nil {
@ -593,6 +601,8 @@ func (st SignatureType) String() string {
return "signature-unknown" return "signature-unknown"
case SignatureV1: case SignatureV1:
return "signature-v1" return "signature-v1"
case SignatureV2:
return "signature-v2"
default: default:
return fmt.Sprintf("signature-unknown(%d)", int(st)) return fmt.Sprintf("signature-unknown(%d)", int(st))
} }