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 }