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 }