From 18c61afeb9ebec3169aab0e2fa75c996de84a250 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Wed, 19 Oct 2022 18:46:18 -0700 Subject: [PATCH] types/key: add ChallengePublic, ChallengePrivate, NewChallenge Updates #5972 Signed-off-by: Brad Fitzpatrick --- types/key/chal.go | 78 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 types/key/chal.go diff --git a/types/key/chal.go b/types/key/chal.go new file mode 100644 index 000000000..17822feed --- /dev/null +++ b/types/key/chal.go @@ -0,0 +1,78 @@ +// Copyright (c) 2022 Tailscale Inc & AUTHORS All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package key + +import ( + "errors" + + "tailscale.com/types/structs" +) + +const ( + // chalPublicHexPrefix is the prefix used to identify a + // hex-encoded challenge public key. + // + // This prefix is used in the control protocol, so cannot be + // changed. + chalPublicHexPrefix = "chalpub:" +) + +// ChallengePrivate is a challenge key, used to test whether clients control a +// key they want to prove ownership of. +// +// A ChallengePrivate is ephemeral and not serialized to the disk or network. +type ChallengePrivate struct { + _ structs.Incomparable // because == isn't constant-time + k [32]byte +} + +// NewChallenge creates and returns a new node private key. +func NewChallenge() ChallengePrivate { + return ChallengePrivate(NewNode()) +} + +// Public returns the ChallengePublic for k. +// Panics if ChallengePublic is zero. +func (k ChallengePrivate) Public() ChallengePublic { + pub := NodePrivate(k).Public() + return ChallengePublic(pub) +} + +// MarshalText implements encoding.TextMarshaler, but by returning an error. +// It shouldn't need to be marshalled anywhere. +func (k ChallengePrivate) MarshalText() ([]byte, error) { + return nil, errors.New("refusing to marshal") +} + +// SealToChallenge is like SealTo, but for a ChallengePublic. +func (k NodePrivate) SealToChallenge(p ChallengePublic, cleartext []byte) (ciphertext []byte) { + return k.SealTo(NodePublic(p), cleartext) +} + +// OpenFrom opens the NaCl box ciphertext, which must be a value +// created by NodePrivate.SealToChallenge, and returns the inner cleartext if +// ciphertext is a valid box from p to k. +func (k ChallengePrivate) OpenFrom(p NodePublic, ciphertext []byte) (cleartext []byte, ok bool) { + return NodePrivate(k).OpenFrom(p, ciphertext) +} + +// ChallengePublic is the public portion of a ChallengePrivate. +type ChallengePublic struct { + k [32]byte +} + +// String returns the output of MarshalText as a string. +func (k ChallengePublic) String() string { + bs, err := k.MarshalText() + if err != nil { + panic(err) + } + return string(bs) +} + +// MarshalText implements encoding.TextMarshaler. +func (k ChallengePublic) MarshalText() ([]byte, error) { + return toHex(k.k[:], chalPublicHexPrefix), nil +}