github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/libkb/delegatekey.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  	"encoding/hex"
     8  	"fmt"
     9  
    10  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    11  	jsonw "github.com/keybase/go-jsonw"
    12  )
    13  
    14  // Delegator
    15  //
    16  // Delegates authority to another key.
    17  //
    18  
    19  type Delegator struct {
    20  	Contextified
    21  
    22  	// Set these fields
    23  	NewKey               GenericKey
    24  	ExistingKey          GenericKey
    25  	EldestKID            keybase1.KID
    26  	Me                   *User
    27  	Expire               int
    28  	Device               *Device
    29  	RevSig               string
    30  	ServerHalf           []byte
    31  	EncodedPrivateKey    string
    32  	Ctime                int64
    33  	DelegationType       DelegationType
    34  	Aggregated           bool // During aggregation we skip some steps (posting, updating some state)
    35  	PerUserKeyGeneration keybase1.PerUserKeyGeneration
    36  	MerkleRoot           *MerkleRoot
    37  
    38  	// Optional precalculated values used by KeyProof
    39  	Seqno       keybase1.Seqno // kex2 HandleDidCounterSign needs to sign subkey without a user but we know what the last seqno was
    40  	PrevLinkID  LinkID         // kex2 HandleDidCounterSign calculates previous link id without a user
    41  	SigningUser UserBasic      // kex2 doesn't have a full user, but does have basic user info
    42  
    43  	// Internal fields
    44  	proof        *ProofMetadataRes
    45  	sig          string
    46  	sigID        keybase1.SigID
    47  	linkID       LinkID
    48  	merkleTriple MerkleTriple
    49  	postArg      APIArg
    50  }
    51  
    52  func (d Delegator) getSigningKID() keybase1.KID { return d.GetSigningKey().GetKID() }
    53  
    54  func (d Delegator) getExistingKID() (kid keybase1.KID) {
    55  	if d.ExistingKey == nil {
    56  		return
    57  	}
    58  	return d.ExistingKey.GetKID()
    59  }
    60  
    61  func (d Delegator) getMerkleHashMeta() (ret keybase1.HashMeta) {
    62  	if d.MerkleRoot == nil {
    63  		return ret
    64  	}
    65  	return d.MerkleRoot.ShortHash().ExportToHashMeta()
    66  }
    67  
    68  func (d Delegator) GetSigningKey() GenericKey {
    69  	if d.ExistingKey != nil {
    70  		return d.ExistingKey
    71  	}
    72  	return d.NewKey
    73  }
    74  
    75  func (d Delegator) IsSibkeyOrEldest() bool {
    76  	return d.DelegationType == DelegationTypeSibkey || d.DelegationType == DelegationTypeEldest
    77  }
    78  
    79  func (d Delegator) IsEldest() bool { return d.DelegationType == DelegationTypeEldest }
    80  
    81  // GetMerkleTriple gets the new MerkleTriple that came about as a result
    82  // of performing the key delegation.
    83  func (d Delegator) GetMerkleTriple() MerkleTriple { return d.merkleTriple }
    84  
    85  func (d *Delegator) CheckArgs(m MetaContext) (err error) {
    86  
    87  	defer m.Trace("Delegator#CheckArgs", &err)()
    88  
    89  	if d.DelegationType == "" {
    90  		err = MissingDelegationTypeError{}
    91  	}
    92  
    93  	if d.NewKey == nil {
    94  		err = NoSecretKeyError{}
    95  		return
    96  	}
    97  
    98  	if d.ExistingKey != nil {
    99  		m.Debug("| Picked passed-in signing key")
   100  	} else {
   101  		m.Debug("| Picking new key for an eldest self-sig")
   102  		d.DelegationType = DelegationTypeEldest
   103  	}
   104  
   105  	if d.EldestKID.Exists() || d.IsEldest() {
   106  	} else if kid := d.Me.GetEldestKID(); kid.IsNil() {
   107  		err = NoSigChainError{}
   108  		return err
   109  	} else {
   110  		d.EldestKID = kid
   111  	}
   112  
   113  	m.Debug("| Picked key %s for signing", d.getSigningKID())
   114  
   115  	return nil
   116  }
   117  
   118  // LoadSigningKey can be called before Run() to load the signing key into
   119  // the delegator. This will check the given key first, then a device Key if we have one,
   120  // and otherwise will leave the signing key unset so that we will set it
   121  // as the eldest key on upload.
   122  // m.LoginContext can be nil.
   123  func (d *Delegator) LoadSigningKey(m MetaContext, ui SecretUI) (err error) {
   124  	defer m.Trace("Delegator#LoadSigningKey", &err)()
   125  
   126  	if d.ExistingKey != nil {
   127  		m.Debug("| Was set ahead of time")
   128  		return nil
   129  	}
   130  
   131  	if d.Me == nil {
   132  		d.Me, err = LoadMe(NewLoadUserPubOptionalArg(d.G()))
   133  		if err != nil {
   134  			return err
   135  		}
   136  		if d.Me == nil {
   137  			m.Debug("| Me didn't load")
   138  			return nil
   139  		}
   140  	}
   141  
   142  	if !d.Me.HasActiveKey() {
   143  		m.Debug("| PGPKeyImportEngine: no active key found, so assuming set of eldest key")
   144  		return nil
   145  	}
   146  
   147  	arg := SecretKeyPromptArg{
   148  		Ska: SecretKeyArg{
   149  			Me:      d.Me,
   150  			KeyType: DeviceSigningKeyType,
   151  		},
   152  		SecretUI: ui,
   153  		Reason:   "sign new key",
   154  	}
   155  	d.ExistingKey, err = m.G().Keyrings.GetSecretKeyWithPrompt(m, arg)
   156  
   157  	return err
   158  }
   159  
   160  // Run the Delegator, performing all necessary internal operations.  Return err
   161  // on failure and nil on success.
   162  func (d *Delegator) Run(m MetaContext) (err error) {
   163  	var jw *jsonw.Wrapper
   164  	defer m.Trace("Delegator#Run", &err)()
   165  
   166  	if err = d.CheckArgs(m); err != nil {
   167  		return err
   168  	}
   169  
   170  	d.MerkleRoot = m.G().MerkleClient.LastRoot(m)
   171  
   172  	// We'll need to generate two proofs, so set the Ctime
   173  	// so that we get the same time both times
   174  	d.Ctime = m.G().Clock().Now().Unix()
   175  
   176  	// For a sibkey signature, we first sign the blob with the
   177  	// sibkey, and then embed that signature for the delegating key
   178  	if d.DelegationType == DelegationTypeSibkey {
   179  		if jw, err = KeyProof(m, *d); err != nil {
   180  			m.Debug("| Failure in intermediate KeyProof()")
   181  			return err
   182  		}
   183  
   184  		if d.RevSig, _, _, err = SignJSON(jw, d.NewKey); err != nil {
   185  			m.Debug("| Failure in intermediate SignJson()")
   186  			return err
   187  		}
   188  	}
   189  
   190  	if m.G().LocalDb == nil {
   191  		panic("should have a local DB")
   192  	}
   193  
   194  	proof, err := KeyProof2(m, *d)
   195  	if err != nil {
   196  		m.Debug("| Failure in KeyProof2()")
   197  		return err
   198  	}
   199  
   200  	return d.SignAndPost(m, proof)
   201  }
   202  
   203  func (d *Delegator) SignAndPost(m MetaContext, proof *ProofMetadataRes) (err error) {
   204  	d.proof = proof
   205  	var sigIDBase keybase1.SigIDBase
   206  	if d.sig, sigIDBase, d.linkID, err = SignJSON(proof.J, d.GetSigningKey()); err != nil {
   207  		m.Debug("| Failure in SignJson()")
   208  		return err
   209  	}
   210  	d.sigID = sigIDBase.ToSigIDLegacy()
   211  	if err = d.post(m); err != nil {
   212  		m.Debug("| Failure in post()")
   213  		return err
   214  	}
   215  	if err = d.updateLocalState(d.linkID); err != nil {
   216  		return err
   217  	}
   218  	return nil
   219  }
   220  
   221  func (d *Delegator) isHighDelegator() bool {
   222  	return d.DelegationType == DelegationTypeEldest ||
   223  		d.DelegationType == DelegationTypeSibkey ||
   224  		d.DelegationType == DelegationTypePGPUpdate
   225  }
   226  
   227  func (d *Delegator) updateLocalState(linkID LinkID) (err error) {
   228  	d.Me.SigChainBump(linkID, d.sigID, d.isHighDelegator())
   229  	d.merkleTriple = MerkleTriple{LinkID: linkID, SigID: d.sigID.StripSuffix()}
   230  	return d.Me.localDelegateKey(d.NewKey, d.sigID, d.getExistingKID(), d.IsSibkeyOrEldest(), d.IsEldest(), d.getMerkleHashMeta(), keybase1.Seqno(0))
   231  }
   232  
   233  func (d *Delegator) post(m MetaContext) (err error) {
   234  	var pub string
   235  	if pub, err = d.NewKey.Encode(); err != nil {
   236  		return
   237  	}
   238  
   239  	hargs := HTTPArgs{
   240  		"sig_id_base":     S{Val: d.sigID.StripSuffix().String()},
   241  		"sig_id_short":    S{Val: d.sigID.ToShortID()},
   242  		"sig":             S{Val: d.sig},
   243  		"type":            S{Val: string(d.DelegationType)},
   244  		"is_remote_proof": B{Val: false},
   245  		"public_key":      S{Val: pub},
   246  	}
   247  
   248  	if len(string(d.ServerHalf)) > 0 {
   249  		hargs["server_half"] = S{Val: hex.EncodeToString(d.ServerHalf)}
   250  	}
   251  
   252  	if d.DelegationType == DelegationTypePGPUpdate {
   253  		hargs["is_update"] = B{Val: true}
   254  	}
   255  
   256  	if d.IsEldest() {
   257  		hargs["is_primary"] = I{Val: 1}
   258  		hargs["new_eldest"] = B{Val: true}
   259  		hargs["signing_kid"] = S{Val: d.NewKey.GetKID().String()}
   260  	} else {
   261  		hargs["eldest_kid"] = d.EldestKID
   262  		hargs["signing_kid"] = d.getSigningKID()
   263  	}
   264  	if len(d.EncodedPrivateKey) > 0 {
   265  		hargs["private_key"] = S{Val: d.EncodedPrivateKey}
   266  	}
   267  
   268  	arg := APIArg{
   269  		Endpoint:    "key/add",
   270  		SessionType: APISessionTypeREQUIRED,
   271  		Args:        hargs,
   272  	}
   273  	if d.Aggregated {
   274  		d.postArg = arg
   275  		// Don't post to the server. DelegatorAggregator will do that.
   276  		return nil
   277  	}
   278  	_, err = m.G().API.Post(m, arg)
   279  	if err != nil {
   280  		return err
   281  	}
   282  	if d.Me == nil {
   283  		return fmt.Errorf("delegator missing 'me' info")
   284  	}
   285  	if d.proof == nil {
   286  		return fmt.Errorf("delegator missing proof seqno")
   287  	}
   288  	return MerkleCheckPostedUserSig(m, d.Me.GetUID(), d.proof.Seqno, d.linkID)
   289  }