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  }