github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/libkb/keymerge.go (about) 1 // Copyright 2015 Keybase, Inc. All rights reserved. Use of 2 // this source code is governed by the included BSD license. 3 4 package libkb 5 6 import ( 7 "crypto" 8 9 "github.com/keybase/go-crypto/openpgp/packet" 10 ) 11 12 func combineSignatures(toSignatures []*packet.Signature, fromSignatures []*packet.Signature) (ret []*packet.Signature) { 13 ret = toSignatures 14 existingSignatures := make(map[crypto.Hash]bool) 15 for _, signature := range toSignatures { 16 existingSignatures[signature.Hash] = true 17 } 18 for _, signature := range fromSignatures { 19 if _, haveSignature := existingSignatures[signature.Hash]; haveSignature { 20 continue 21 } 22 ret = append(ret, signature) 23 } 24 return 25 } 26 27 // MergeKey adds the identities, revocations, and subkeys of another PGPKeyBundle to this key 28 func (to *PGPKeyBundle) MergeKey(from *PGPKeyBundle) { 29 30 // First, merge identities, adding any signatures found in matching identities 31 for name, fromIdentity := range from.Identities { 32 if toIdentity, ok := to.Identities[name]; ok { 33 to.Identities[name].Signatures = combineSignatures(toIdentity.Signatures, fromIdentity.Signatures) 34 35 // There's a primary self-signature that we use. Always take the later 36 // of the two. 37 ssTo := to.Identities[name].SelfSignature 38 ssFrom := fromIdentity.SelfSignature 39 if ssFrom.CreationTime.After(ssTo.CreationTime) { 40 to.Identities[name].SelfSignature = ssFrom 41 } 42 43 } else { 44 to.Identities[fromIdentity.Name] = fromIdentity 45 } 46 } 47 48 // Then, merge revocations 49 to.Revocations = combineSignatures(to.Revocations, from.Revocations) 50 51 // Finally, merge subkeys 52 existingSubkeys := make(map[[20]byte]int) 53 for i, subkey := range to.Subkeys { 54 existingSubkeys[subkey.PublicKey.Fingerprint] = i 55 } 56 for _, subkey := range from.Subkeys { 57 if i, ok := existingSubkeys[subkey.PublicKey.Fingerprint]; ok { 58 if subkey.Sig.CreationTime.After(to.Subkeys[i].Sig.CreationTime) { 59 to.Subkeys[i].Sig = subkey.Sig 60 if subkey.Revocation != nil { 61 to.Subkeys[i].Revocation = subkey.Revocation 62 } 63 } 64 } else { 65 to.Subkeys = append(to.Subkeys, subkey) 66 } 67 } 68 }