diff --git a/tka/sig.go b/tka/sig.go index fc2d94023..368fb96ad 100644 --- a/tka/sig.go +++ b/tka/sig.go @@ -116,6 +116,27 @@ func (s NodeKeySignature) wrappingPublic() (pub ed25519.PublicKey, ok bool) { } } +// authorizingKeyID returns the KeyID of the key trusted by network-lock which authorizes +// this signature. +func (s NodeKeySignature) authorizingKeyID() (tkatype.KeyID, error) { + switch s.SigKind { + case SigDirect, SigCredential: + if len(s.KeyID) == 0 { + return tkatype.KeyID{}, errors.New("invalid signature: no keyID present") + } + return tkatype.KeyID(s.KeyID), nil + + case SigRotation: + if s.Nested == nil { + return tkatype.KeyID{}, errors.New("invalid signature: rotation signature missing nested signature") + } + return s.Nested.authorizingKeyID() + + default: + return tkatype.KeyID{}, fmt.Errorf("unhandled signature type: %v", s.SigKind) + } +} + // SigHash returns the cryptographic digest which a signature // is over. // diff --git a/tka/sig_test.go b/tka/sig_test.go index a8536611c..e036ac717 100644 --- a/tka/sig_test.go +++ b/tka/sig_test.go @@ -79,7 +79,6 @@ func TestSigNested(t *testing.T) { // rotation key & embedding the original signature. sig := NodeKeySignature{ SigKind: SigRotation, - KeyID: k.ID(), Pubkey: nodeKeyPub, Nested: &nestedSig, } @@ -145,14 +144,13 @@ func TestSigNested_DeepNesting(t *testing.T) { outer := nestedSig var lastNodeKey key.NodePrivate - for i := 0; i < 100; i++ { + for i := 0; i < 15; i++ { // 15 = max nesting level for CBOR lastNodeKey = key.NewNode() nodeKeyPub, _ := lastNodeKey.Public().MarshalBinary() tmp := outer sig := NodeKeySignature{ SigKind: SigRotation, - KeyID: k.ID(), Pubkey: nodeKeyPub, Nested: &tmp, } @@ -166,6 +164,16 @@ func TestSigNested_DeepNesting(t *testing.T) { t.Fatalf("verifySignature(lastNodeKey) failed: %v", err) } + // Test this works with our public API + a, _ := Open(newTestchain(t, "G1\nG1.template = genesis", + optTemplate("genesis", AUM{MessageKind: AUMCheckpoint, State: &State{ + Keys: []Key{k}, + DisablementSecrets: [][]byte{DisablementKDF([]byte{1, 2, 3})}, + }})).Chonk()) + if err := a.NodeKeyAuthorized(lastNodeKey.Public(), outer.Serialize()); err != nil { + t.Errorf("NodeKeyAuthorized(lastNodeKey) failed: %v", err) + } + // Test verification fails if the inner signature is invalid tmp := make([]byte, ed25519.SignatureSize) copy(tmp, nestedSig.Signature) @@ -206,7 +214,6 @@ func TestSigCredential(t *testing.T) { // delegated key & embedding the original signature. sig := NodeKeySignature{ SigKind: SigRotation, - KeyID: k.ID(), Pubkey: nodeKeyPub, Nested: &nestedSig, } diff --git a/tka/tka.go b/tka/tka.go index e2094a221..2c7168afc 100644 --- a/tka/tka.go +++ b/tka/tka.go @@ -686,7 +686,12 @@ func (a *Authority) NodeKeyAuthorized(nodeKey key.NodePublic, nodeKeySignature t return errors.New("credential signatures cannot authorize nodes on their own") } - key, err := a.state.GetKey(decoded.KeyID) + kID, err := decoded.authorizingKeyID() + if err != nil { + return err + } + + key, err := a.state.GetKey(kID) if err != nil { return fmt.Errorf("key: %v", err) }