github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/sig3/sig3.go (about)

     1  package sig3
     2  
     3  import (
     4  	"crypto/hmac"
     5  	"crypto/rand"
     6  	"crypto/sha256"
     7  	"encoding/base64"
     8  	"encoding/hex"
     9  	"github.com/keybase/client/go/kbcrypto"
    10  	"github.com/keybase/client/go/msgpack"
    11  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    12  	"github.com/keybase/go-crypto/ed25519"
    13  )
    14  
    15  // Generic sig3 wrapper class, should implement the following interface.
    16  type Generic interface {
    17  	Signer() *Signer
    18  	Prev() *LinkID
    19  	Seqno() Seqno
    20  	Outer() OuterLink
    21  	Inner() *InnerLink
    22  
    23  	// Inner methods for generic decoding of incoming sig3 links
    24  	outerPointer() *OuterLink
    25  
    26  	// setVerifiedBit is called once we've verified the outer signature over the whole
    27  	// link, and also any inner reverse signatures. If any verification fails, the bit
    28  	// will not get set. The bit also won't get set for stubbed links, since there isn't
    29  	// enough information to verify.
    30  	setVerifiedBit()
    31  	verify() error
    32  
    33  	// check this chainlink after parsing for type-specific properties
    34  	parseCheck() error
    35  }
    36  
    37  // Base struct for sig3 links that contains much of the raw material pulled down or off local storage.
    38  // Most implementations of sig3 links should include this base class.
    39  type Base struct {
    40  	verified bool // see message above for when this bit is set.
    41  	inner    *InnerLink
    42  	outerRaw []byte
    43  	outer    OuterLink
    44  	sig      *Sig
    45  }
    46  
    47  // RotateKey is a sig3 link type for a PTK rotation. Handles multiple PTK types being rotated in
    48  // one link.
    49  type RotateKey struct {
    50  	Base
    51  }
    52  
    53  // LinkFromFuture is a sig3 link type that we don't know how to decode, but it's ok to ignore.
    54  type LinkFromFuture struct {
    55  	Base
    56  }
    57  
    58  var _ Generic = (*Base)(nil)
    59  var _ Generic = (*RotateKey)(nil)
    60  var _ Generic = (*LinkFromFuture)(nil)
    61  
    62  // NewRotateKey makes a new rotate key given sig3 skeletons (Outer and Inner) and
    63  // also the PTKs that are going to be advertised in the sig3 link.
    64  func NewRotateKey(o OuterLink, i InnerLink, b RotateKeyBody) *RotateKey {
    65  	i.Body = &b
    66  	return &RotateKey{
    67  		Base: Base{
    68  			inner: &i,
    69  			outer: o,
    70  		},
    71  	}
    72  }
    73  
    74  // rkb returns the RotateKeyBody that we are expecting at r.Base.inner. It should never fail, if it does,
    75  // the program will crash.
    76  func (r *RotateKey) rkb() *RotateKeyBody {
    77  	ret, _ := r.Base.inner.Body.(*RotateKeyBody)
    78  	return ret
    79  }
    80  
    81  func (r *RotateKey) PTKs() []PerTeamKey {
    82  	return r.rkb().PTKs
    83  }
    84  
    85  func (r *RotateKey) ReaderKey() *PerTeamKey {
    86  	for _, k := range r.rkb().PTKs {
    87  		if k.PTKType == keybase1.PTKType_READER {
    88  			return &k
    89  		}
    90  	}
    91  	return nil
    92  }
    93  
    94  func (b *Base) setVerifiedBit() {
    95  	if b.inner != nil && b.sig != nil {
    96  		b.verified = true
    97  	}
    98  }
    99  
   100  func (b *Base) parseCheck() error {
   101  	return nil
   102  }
   103  
   104  // Outer returns a copy of the OuterLink in this base class
   105  func (b *Base) Outer() OuterLink {
   106  	return b.outer
   107  }
   108  
   109  func (b *Base) outerPointer() *OuterLink {
   110  	return &b.outer
   111  }
   112  
   113  // Inner returns a pointer to the InnerLink in this base class.
   114  func (b *Base) Inner() *InnerLink {
   115  	return b.inner
   116  }
   117  
   118  // Signer returns the (uid, eldest, KID) of the signer of this link if a sig was provided,
   119  // and it was successfully verified (as reported by the link itself). If not, then this will
   120  // return a nil.
   121  func (b *Base) Signer() *Signer {
   122  	if !b.verified {
   123  		return nil
   124  	}
   125  	if b.inner == nil {
   126  		return nil
   127  	}
   128  	return &b.inner.Signer
   129  }
   130  
   131  // Prev returns the LinkID of the previous link, or nil if none was provided.
   132  func (b *Base) Prev() *LinkID {
   133  	return b.outer.Prev
   134  }
   135  
   136  // Seqno returns the seqno of this link, as reported in the outer link itself.
   137  func (b *Base) Seqno() Seqno {
   138  	return b.outer.Seqno
   139  }
   140  
   141  func (b Base) verify() error {
   142  	if (b.sig == nil) != (b.inner == nil) {
   143  		return newSig3Error("need sig and inner, or neither, but can't have one and not the other (sig: %v, inner: %v)", (b.sig != nil), (b.inner != nil))
   144  	}
   145  	if b.sig == nil || b.inner == nil {
   146  		return nil
   147  	}
   148  	err := b.sig.verify(b.inner.Signer.KID, b.outerRaw)
   149  	if err != nil {
   150  		return err
   151  	}
   152  	return nil
   153  }
   154  
   155  func (i InnerLink) hash() (LinkID, error) {
   156  	return hashInterface(i)
   157  }
   158  
   159  func hashInterface(i interface{}) (LinkID, error) {
   160  	b, err := msgpack.Encode(i)
   161  	if err != nil {
   162  		return LinkID{}, err
   163  	}
   164  	return hash(b), nil
   165  }
   166  
   167  func (l LinkID) String() string {
   168  	return hex.EncodeToString(l[:])
   169  }
   170  
   171  func (o OuterLink) Hash() (LinkID, error) {
   172  	return hashInterface(o)
   173  }
   174  
   175  func (r RotateKey) verify() error {
   176  	err := r.Base.verify()
   177  	if err != nil {
   178  		return err
   179  	}
   180  	err = r.verifyReverseSig()
   181  	if err != nil {
   182  		return err
   183  	}
   184  	return nil
   185  }
   186  
   187  func (r RotateKey) verifyReverseSig() (err error) {
   188  	if r.inner == nil {
   189  		return nil
   190  	}
   191  
   192  	// First make a checkpoint of all of the previous sigs and the previous inner
   193  	// link, since we're going to mutate them as we verify
   194  	var reverseSigs []*Sig
   195  	for _, ptk := range r.rkb().PTKs {
   196  		reverseSigs = append(reverseSigs, ptk.ReverseSig)
   197  	}
   198  	innerLinkID := r.Base.outer.InnerLinkID
   199  
   200  	// Make sure to replace them on the way out of the function, even in an error.
   201  	defer func() {
   202  		for j, rs := range reverseSigs {
   203  			r.rkb().PTKs[j].ReverseSig = rs
   204  		}
   205  		r.Base.outer.InnerLinkID = innerLinkID
   206  	}()
   207  
   208  	// Verify signatures in the reverse order they were signed, nulling them out
   209  	// from back to front. We are not going middle-out.
   210  	for i := len(r.rkb().PTKs) - 1; i >= 0; i-- {
   211  		ptk := &r.rkb().PTKs[i]
   212  		revSig := ptk.ReverseSig
   213  		if revSig == nil {
   214  			return newSig3Error("rotate key link is missing a reverse sig")
   215  		}
   216  
   217  		ptk.ReverseSig = nil
   218  		r.Base.outer.InnerLinkID, err = r.Base.inner.hash()
   219  		if err != nil {
   220  			return err
   221  		}
   222  		b, err := msgpack.Encode(r.Base.outer)
   223  		if err != nil {
   224  			return err
   225  		}
   226  		err = revSig.verify(ptk.SigningKID, b)
   227  		if err != nil {
   228  			return newSig3Error("bad reverse signature: %s", err.Error())
   229  		}
   230  	}
   231  
   232  	return nil
   233  }
   234  
   235  func hash(b []byte) LinkID {
   236  	return LinkID(sha256.Sum256(b))
   237  }
   238  
   239  func (l LinkID) eq(m LinkID) bool {
   240  	return hmac.Equal(l[:], m[:])
   241  }
   242  
   243  func (s ExportJSON) parseSig() (*Base, error) {
   244  	var out Base
   245  	if s.Sig == "" {
   246  		return &out, nil
   247  	}
   248  	b, err := base64.StdEncoding.DecodeString(s.Sig)
   249  	if err != nil {
   250  		return nil, err
   251  	}
   252  	out.sig = &Sig{}
   253  	err = msgpack.Decode(&out.sig, b)
   254  	if err != nil {
   255  		return nil, err
   256  	}
   257  	return &out, nil
   258  }
   259  
   260  func (s ExportJSON) parseOuter(in Base) (*Base, error) {
   261  	if s.Outer == "" {
   262  		return nil, newParseError("outer cannot be nil")
   263  	}
   264  	b, err := base64.StdEncoding.DecodeString(s.Outer)
   265  	if err != nil {
   266  		return nil, err
   267  	}
   268  	in.outerRaw = b
   269  	if !msgpack.IsEncodedMsgpackArray(b) {
   270  		return nil, newParseError("need an encoded msgpack array (with no leading garbage)")
   271  	}
   272  	err = msgpack.Decode(&in.outer, b)
   273  	if err != nil {
   274  		return nil, err
   275  	}
   276  	if in.outer.Version != SigVersion3 {
   277  		return nil, newSig3Error("can only handle sig version 3 (got %d)", in.outer.Version)
   278  	}
   279  	if in.outer.ChainType != ChainTypeTeamPrivateHidden {
   280  		return nil, newSig3Error("can only handle type 17 (team private hidden)")
   281  	}
   282  	return &in, nil
   283  }
   284  
   285  func (r *RotateKey) parseCheck() error {
   286  	m := make(map[keybase1.PTKType]bool)
   287  	for _, k := range r.rkb().PTKs {
   288  		typ := k.PTKType
   289  		if m[typ] {
   290  			return newParseError("duplicated PTK type: %s", typ)
   291  		}
   292  		m[typ] = true
   293  	}
   294  	return nil
   295  }
   296  
   297  func (s *ExportJSON) parseInner(in Base) (Generic, error) {
   298  	var out Generic
   299  
   300  	if (s.Inner == "") != (in.sig == nil) {
   301  		return nil, newParseError("need a sig and an inner, or neither, but not one without the other (sig: %v, inner: %v)", (in.sig != nil), (s.Inner != ""))
   302  	}
   303  
   304  	if s.Inner == "" {
   305  		return &in, nil
   306  	}
   307  
   308  	b, err := base64.StdEncoding.DecodeString(s.Inner)
   309  	if err != nil {
   310  		return nil, err
   311  	}
   312  
   313  	if !hash(b).eq(in.outer.InnerLinkID) {
   314  		return nil, newSig3Error("inner link hash doesn't match inner")
   315  	}
   316  
   317  	in.inner = &InnerLink{}
   318  	switch in.outer.LinkType {
   319  	case LinkTypeRotateKey:
   320  		var rkb RotateKeyBody
   321  		in.inner.Body = &rkb
   322  		out = &RotateKey{Base: in}
   323  	default:
   324  		if !in.outer.IgnoreIfUnsupported {
   325  			return nil, newParseError("unknown link type %d", in.outer.LinkType)
   326  		}
   327  		// Make it seem like a stubbed link
   328  		out = &LinkFromFuture{Base: in}
   329  	}
   330  
   331  	err = msgpack.Decode(in.inner, b)
   332  	if err != nil {
   333  		return nil, err
   334  	}
   335  
   336  	err = out.parseCheck()
   337  	if err != nil {
   338  		return nil, err
   339  	}
   340  
   341  	return out, nil
   342  }
   343  
   344  func (s ExportJSON) parse() (out Generic, err error) {
   345  	var tmp *Base
   346  	tmp, err = s.parseSig()
   347  	if err != nil {
   348  		return nil, err
   349  	}
   350  	tmp, err = s.parseOuter(*tmp)
   351  	if err != nil {
   352  		return nil, err
   353  	}
   354  	out, err = s.parseInner(*tmp)
   355  	if err != nil {
   356  		return nil, err
   357  	}
   358  	return out, nil
   359  }
   360  
   361  // Import from ExportJSON format (as sucked down from the server) into a Generic link type,
   362  // that can be casted into the supported link types (like RotateKey). Returns an error if we
   363  // failed to parse the input data, or if signature validation failed.
   364  func (s ExportJSON) Import() (Generic, error) {
   365  	out, err := s.parse()
   366  	if err != nil {
   367  		return nil, err
   368  	}
   369  	err = out.verify()
   370  	if err != nil {
   371  		return nil, err
   372  	}
   373  	out.setVerifiedBit()
   374  	return out, nil
   375  }
   376  
   377  func (sig Sig) verify(kid KID, body []byte) error {
   378  	key := kbcrypto.KIDToNaclSigningKeyPublic([]byte(kid))
   379  	if key == nil {
   380  		return newSig3Error("failed to import public key")
   381  	}
   382  	msg := kbcrypto.SignaturePrefixSigchain3.Prefix(body)
   383  	if !ed25519.Verify(key[:], msg, sig[:]) {
   384  		return newSig3Error("signature verification failed")
   385  	}
   386  	return nil
   387  }
   388  
   389  type KeyPair struct {
   390  	priv kbcrypto.NaclSigningKeyPrivate
   391  	pub  KID
   392  }
   393  
   394  func NewKeyPair(priv kbcrypto.NaclSigningKeyPrivate, pub KID) *KeyPair {
   395  	return &KeyPair{priv, pub}
   396  }
   397  
   398  func genRandomBytes(i int) ([]byte, error) {
   399  	ret := make([]byte, i)
   400  	n, err := rand.Read(ret)
   401  	if err != nil {
   402  		return nil, err
   403  	}
   404  	if n != i {
   405  		return nil, newSig3Error("short random entropy read")
   406  	}
   407  	return ret, nil
   408  }
   409  
   410  // Sign the RotateKey structure, with the given user's keypair (outer), and with the new
   411  // PTKs (inner). Return a Sig3Bundle, which was the exportable information, that you can
   412  // export either to local storage or up to the server.
   413  func (r RotateKey) Sign(outer KeyPair, inners []KeyPair) (ret *Sig3Bundle, err error) {
   414  	i := r.Inner()
   415  	o := r.outerPointer()
   416  	if i == nil {
   417  		return nil, newSig3Error("cannot sign without an inner link")
   418  	}
   419  
   420  	o.Version = SigVersion3
   421  	o.LinkType = LinkTypeRotateKey
   422  	o.ChainType = ChainTypeTeamPrivateHidden
   423  	i.Signer.KID = outer.pub
   424  	if i.Entropy == nil {
   425  		i.Entropy, err = genRandomBytes(16)
   426  		if err != nil {
   427  			return nil, err
   428  		}
   429  	}
   430  
   431  	for j := range r.rkb().PTKs {
   432  		ptk := &r.rkb().PTKs[j]
   433  		ptk.ReverseSig = nil
   434  		ptk.SigningKID = inners[j].pub
   435  	}
   436  
   437  	for j := range r.rkb().PTKs {
   438  		ptk := &r.rkb().PTKs[j]
   439  		tmp, err := signGeneric(&r.Base, inners[j].priv)
   440  		if err != nil {
   441  			return nil, err
   442  		}
   443  		ptk.ReverseSig = tmp.Sig
   444  	}
   445  	return signGeneric(&r.Base, outer.priv)
   446  }
   447  
   448  func signGeneric(g Generic, privkey kbcrypto.NaclSigningKeyPrivate) (ret *Sig3Bundle, err error) {
   449  	o := g.Outer()
   450  	i := g.Inner()
   451  	if i == nil {
   452  		return nil, newSig3Error("cannot sign without an inner link")
   453  	}
   454  	o.InnerLinkID, err = i.hash()
   455  	if err != nil {
   456  		return nil, err
   457  	}
   458  	b, err := msgpack.Encode(o)
   459  	if err != nil {
   460  		return nil, err
   461  	}
   462  	var sig Sig
   463  	msg := kbcrypto.SignaturePrefixSigchain3.Prefix(b)
   464  	copy(sig[:], ed25519.Sign(privkey[:], msg))
   465  	return &Sig3Bundle{
   466  		Sig:   &sig,
   467  		Inner: i,
   468  		Outer: o,
   469  	}, nil
   470  }
   471  
   472  // Export a sig3 up to the server in base64'ed JSON format, as in a POST request.
   473  func (s Sig3Bundle) Export() (ret ExportJSON, err error) {
   474  	enc := func(i interface{}) (string, error) {
   475  		b, err := msgpack.Encode(i)
   476  		if err != nil {
   477  			return "", err
   478  		}
   479  		return base64.StdEncoding.EncodeToString(b), nil
   480  	}
   481  	ret.Outer, err = enc(s.Outer)
   482  	if err != nil {
   483  		return ret, err
   484  	}
   485  	if s.Inner != nil {
   486  		ret.Inner, err = enc(s.Inner)
   487  		if err != nil {
   488  			return ret, err
   489  		}
   490  	}
   491  	if s.Sig != nil {
   492  		ret.Sig, err = enc(s.Sig[:])
   493  		if err != nil {
   494  			return ret, nil
   495  		}
   496  	}
   497  	return ret, nil
   498  }
   499  
   500  func IsStubbed(g Generic) bool {
   501  	return g.Inner() == nil
   502  }
   503  
   504  func Hash(g Generic) (LinkID, error) {
   505  	return g.Outer().Hash()
   506  }
   507  
   508  func CheckLinkSequence(v []Generic) error {
   509  	if len(v) == 0 {
   510  		return nil
   511  	}
   512  	prev := v[0]
   513  	for _, link := range v[1:] {
   514  		if prev.Seqno()+keybase1.Seqno(1) != link.Seqno() {
   515  			return newSequenceError("seqno mismatch at link %d", link.Seqno())
   516  		}
   517  		hsh, err := Hash(prev)
   518  		if err != nil {
   519  			return newSequenceError("bad prev hash computation at %d: %s", link.Seqno(), err.Error())
   520  		}
   521  		if link.Prev() == nil {
   522  			return newSequenceError("bad nil prev at %d", link.Seqno())
   523  		}
   524  		if !hsh.eq(*link.Prev()) {
   525  			return newSequenceError("prev hash mismatch at %d", link.Seqno())
   526  		}
   527  		prev = link
   528  	}
   529  	return nil
   530  }