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

     1  package sig3
     2  
     3  import (
     4  	"crypto/rand"
     5  	"encoding/base64"
     6  	"github.com/keybase/client/go/msgpack"
     7  	"github.com/keybase/go-crypto/ed25519"
     8  	"github.com/stretchr/testify/require"
     9  	"testing"
    10  	"time"
    11  )
    12  
    13  func genKey(t *testing.T) (pair KeyPair) {
    14  	publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader)
    15  	require.NoError(t, err)
    16  	copy(pair.priv[:], privateKey[:])
    17  	pair.pub = makeKID(publicKey[:], 0x20)
    18  	return pair
    19  }
    20  
    21  func genDHKID(t *testing.T) KID {
    22  	return makeKID(randomBytes(t, 32), 0x21)
    23  }
    24  
    25  func makeKID(key []byte, typ byte) KID {
    26  	ret := KID(make([]byte, 35))
    27  	ret[0] = 1
    28  	ret[1] = typ
    29  	ret[34] = 0x0a
    30  	copy(ret[2:34], key)
    31  	return ret
    32  }
    33  
    34  func randomBytes(t *testing.T, i int) []byte {
    35  	ret, err := genRandomBytes(i)
    36  	require.NoError(t, err)
    37  	return ret
    38  }
    39  
    40  func randomUID(t *testing.T) UID {
    41  	var ret UID
    42  	b := randomBytes(t, len(ret))
    43  	copy(ret[:], b)
    44  	return ret
    45  }
    46  
    47  func randomTeamID(t *testing.T) TeamID {
    48  	var ret TeamID
    49  	b := randomBytes(t, len(ret))
    50  	copy(ret[:], b)
    51  	return ret
    52  }
    53  
    54  func randomLinkIDPointer(t *testing.T) *LinkID {
    55  	var ret LinkID
    56  	b := randomBytes(t, len(ret))
    57  	copy(ret[:], b)
    58  	return &ret
    59  }
    60  
    61  func genTest(t *testing.T, n int) (bun *Sig3Bundle, ex ExportJSON, rk *RotateKey, outerKey KeyPair, innerKey []KeyPair) {
    62  	now := TimeSec(time.Now().Unix())
    63  	inner := InnerLink{
    64  		Ctime:   now,
    65  		Entropy: randomBytes(t, 16),
    66  		ClientInfo: &ClientInfo{
    67  			Desc:    "foo",
    68  			Version: "1.0.0-1",
    69  		},
    70  		MerkleRoot: MerkleRoot{
    71  			Ctime: now,
    72  			Seqno: 100,
    73  			Hash:  randomBytes(t, 32),
    74  		},
    75  		Signer: Signer{
    76  			EldestSeqno: 1,
    77  			UID:         randomUID(t),
    78  		},
    79  		Team: &Team{
    80  			TeamID:     randomTeamID(t),
    81  			IsPublic:   false,
    82  			IsImplicit: false,
    83  		},
    84  	}
    85  	outer := OuterLink{
    86  		Seqno: Seqno(11),
    87  		Prev:  randomLinkIDPointer(t),
    88  	}
    89  
    90  	var ptks []PerTeamKey
    91  	var innerKeys []KeyPair
    92  	for i := 0; i < n; i++ {
    93  		ptk := PerTeamKey{
    94  			AppkeyDerivationVersion: 1,
    95  			Generation:              PerTeamKeyGeneration(5),
    96  			EncryptionKID:           genDHKID(t),
    97  			PTKType:                 PTKType(i),
    98  		}
    99  		ptks = append(ptks, ptk)
   100  		innerKeys = append(innerKeys, genKey(t))
   101  	}
   102  	rkb := RotateKeyBody{PTKs: ptks}
   103  
   104  	outerKey = genKey(t)
   105  	rk = NewRotateKey(outer, inner, rkb)
   106  	bun, err := rk.Sign(outerKey, innerKeys)
   107  	require.NoError(t, err)
   108  	ex, err = bun.Export()
   109  	require.NoError(t, err)
   110  	return bun, ex, rk, outerKey, innerKeys
   111  }
   112  
   113  func TestSignAndVerifyHappyPath(t *testing.T) {
   114  	_, ex, rk, outerKey, _ := genTest(t, 1)
   115  	generic, err := ex.Import()
   116  	require.NoError(t, err)
   117  	rk2, castOk := generic.(*RotateKey)
   118  	require.True(t, castOk)
   119  	require.NotNil(t, rk2.Signer())
   120  	require.Equal(t, rk2.Signer().KID, outerKey.pub)
   121  	require.Equal(t, rk2.Signer().UID, rk.Base.inner.Signer.UID)
   122  }
   123  
   124  func TestSignAndVerifyHappyPathFourFold(t *testing.T) {
   125  	_, ex, rk, outerKey, _ := genTest(t, 4)
   126  	generic, err := ex.Import()
   127  	require.NoError(t, err)
   128  	rk2, castOk := generic.(*RotateKey)
   129  	require.True(t, castOk)
   130  	require.NotNil(t, rk2.Signer())
   131  	require.Equal(t, rk2.Signer().KID, outerKey.pub)
   132  	require.Equal(t, rk2.Signer().UID, rk.Base.inner.Signer.UID)
   133  	require.Equal(t, len(rk2.rkb().PTKs), 4)
   134  }
   135  
   136  func TestMissingSig(t *testing.T) {
   137  	_, ex, _, _, _ := genTest(t, 1)
   138  	ex.Sig = ""
   139  	_, err := ex.Import()
   140  	require.Error(t, err)
   141  	require.Equal(t, err, newParseError("need a sig and an inner, or neither, but not one without the other (sig: false, inner: true)"))
   142  }
   143  
   144  func TestMissingInner(t *testing.T) {
   145  	_, ex, _, _, _ := genTest(t, 1)
   146  	ex.Inner = ""
   147  	_, err := ex.Import()
   148  	require.Error(t, err)
   149  	require.Equal(t, err, newParseError("need a sig and an inner, or neither, but not one without the other (sig: true, inner: false)"))
   150  }
   151  
   152  func TestStubbed(t *testing.T) {
   153  	_, ex, _, _, _ := genTest(t, 1)
   154  	ex.Sig = ""
   155  	ex.Inner = ""
   156  	rk, err := ex.Import()
   157  	require.NoError(t, err)
   158  	require.Nil(t, rk.Signer())
   159  }
   160  
   161  func TestMissingOuter(t *testing.T) {
   162  	_, ex, _, _, _ := genTest(t, 1)
   163  	ex.Outer = ""
   164  	_, err := ex.Import()
   165  	require.Error(t, err)
   166  	require.Equal(t, err, newParseError("outer cannot be nil"))
   167  }
   168  
   169  func TestLeadingGarbage(t *testing.T) {
   170  	_, ex, _, _, _ := genTest(t, 1)
   171  	ex.Outer = "eyJhYmMi" + ex.Outer
   172  	_, err := ex.Import()
   173  	require.Error(t, err)
   174  	require.Equal(t, err, newParseError("need an encoded msgpack array (with no leading garbage)"))
   175  }
   176  
   177  func TestBadSig(t *testing.T) {
   178  	_, ex, _, _, _ := genTest(t, 1)
   179  	b, err := base64.StdEncoding.DecodeString(ex.Sig)
   180  	require.NoError(t, err)
   181  	b[4] ^= 1
   182  	ex.Sig = base64.StdEncoding.EncodeToString(b)
   183  	_, err = ex.Import()
   184  	require.Error(t, err)
   185  	require.Equal(t, err, newSig3Error("signature verification failed"))
   186  }
   187  
   188  func testMutateOuter(t *testing.T, f func(o *OuterLink), wantedErr error) {
   189  	_, ex, _, _, _ := genTest(t, 1)
   190  	b, err := base64.StdEncoding.DecodeString(ex.Outer)
   191  	require.NoError(t, err)
   192  	var tmp OuterLink
   193  	err = msgpack.Decode(&tmp, b)
   194  	require.NoError(t, err)
   195  	f(&tmp)
   196  	b, err = msgpack.Encode(tmp)
   197  	require.NoError(t, err)
   198  	ex.Outer = base64.StdEncoding.EncodeToString(b)
   199  	_, err = ex.Import()
   200  	require.Error(t, err)
   201  	require.Equal(t, err, wantedErr)
   202  }
   203  
   204  func TestBadPayload(t *testing.T) {
   205  	testMutateOuter(t, func(o *OuterLink) { o.Seqno++ }, newSig3Error("signature verification failed"))
   206  }
   207  
   208  func TestBadInnerLink(t *testing.T) {
   209  	testMutateOuter(t, func(o *OuterLink) { o.InnerLinkID[0] ^= 1 }, newSig3Error("inner link hash doesn't match inner"))
   210  }
   211  
   212  func TestBadVersion(t *testing.T) {
   213  	testMutateOuter(t, func(o *OuterLink) { o.Version = 10 }, newSig3Error("can only handle sig version 3 (got 10)"))
   214  }
   215  
   216  func TestBadChainType(t *testing.T) {
   217  	testMutateOuter(t, func(o *OuterLink) { o.ChainType = 10 }, newSig3Error("can only handle type 17 (team private hidden)"))
   218  }
   219  
   220  func TestBadLinkType(t *testing.T) {
   221  	testMutateOuter(t, func(o *OuterLink) { o.LinkType = 10 }, newParseError("unknown link type 10"))
   222  }
   223  
   224  func (r RotateKey) badSign(outer KeyPair, inner KeyPair, f func(sig *Sig) *Sig) (ret *Sig3Bundle, err error) {
   225  	i := r.Inner()
   226  	o := r.outerPointer()
   227  	if i == nil {
   228  		return nil, newSig3Error("cannot sign without an inner link")
   229  	}
   230  
   231  	o.Version = SigVersion3
   232  	o.LinkType = LinkTypeRotateKey
   233  	o.ChainType = ChainTypeTeamPrivateHidden
   234  
   235  	r.rkb().PTKs[0].ReverseSig = nil
   236  	r.rkb().PTKs[0].SigningKID = inner.pub
   237  	i.Signer.KID = outer.pub
   238  	tmp, err := signGeneric(&r.Base, inner.priv)
   239  	if err != nil {
   240  		return nil, err
   241  	}
   242  	r.rkb().PTKs[0].ReverseSig = f(tmp.Sig)
   243  	return signGeneric(&r.Base, outer.priv)
   244  }
   245  
   246  func TestBadReverseSig(t *testing.T) {
   247  	_, _, rk, outerKey, innerKeys := genTest(t, 1)
   248  	bun, err := rk.badSign(outerKey, innerKeys[0], func(sig *Sig) *Sig { sig[0] ^= 1; return sig })
   249  	require.NoError(t, err)
   250  	ex, err := bun.Export()
   251  	require.NoError(t, err)
   252  	_, err = ex.Import()
   253  	require.Error(t, err)
   254  	require.Equal(t, err, newSig3Error("bad reverse signature: sig3 error: signature verification failed"))
   255  }
   256  
   257  func TestNoReverseSig(t *testing.T) {
   258  	_, _, rk, outerKey, innerKeys := genTest(t, 1)
   259  	bun, err := rk.badSign(outerKey, innerKeys[0], func(sig *Sig) *Sig { return nil })
   260  	require.NoError(t, err)
   261  	ex, err := bun.Export()
   262  	require.NoError(t, err)
   263  	_, err = ex.Import()
   264  	require.Error(t, err)
   265  	require.Equal(t, err, newSig3Error("rotate key link is missing a reverse sig"))
   266  }