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 }