-
Notifications
You must be signed in to change notification settings - Fork 22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
multi: refactor and dynamic auth data #27
Conversation
be578c6
to
157afdd
Compare
mailbox/noise.go
Outdated
@@ -685,7 +713,10 @@ func (b *Machine) GenActTwo() ([ActTwoSize]byte, error) { | |||
|
|||
authPayload := b.EncryptAndHash(payload[:]) | |||
|
|||
actTwo[0] = HandshakeVersion | |||
// The responder will always send its preferred handshake version in | |||
// the hopes that the initiator will then upgrade to this version in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Upgrade to the version in act 2? I think this assumes a lot w.r.t how new versions will be rolled out all together.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reasoning behind this flow is that in our case, the initiator (TW) will always be updated before the responder (Litd) . And since the initiator is also the one that sends the first message (act 1), it makes this negotiation a bit tricky. So we went with this approach:
- Act 1: client sends its lowest acceptable version in act 1 (client cant send its max version here since then every new handshake version would be a breaking change and everyone would need to upgrade their Lit nodes)
- Act 2: server sends its max version. Client will get this and will know which version the server will be happy with and will adapt to that version.
- Act 3: client sends back what ever the server sent in act 2.
Let me know if there is a better way 👍
@ellemouton, remember to re-request review from reviewers when ready |
157afdd
to
d17e479
Compare
Cool, I have changed this PR up quite a lot. Pls see the updated description 👍 |
d17e479
to
dd3efba
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did a first round to familiarize myself with the refactor.
Amazing work on this, it really looks great! And I think I learned a thing or two about the noise handshake 💯
Will need a second round to catch all the details. But in the meantime I'll submit my comments.
The linter also has a few complaints by the way.
dd3efba
to
5d11038
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for taking a look @guggero 🚀 updated 👍
5d11038
to
833972e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great refactor, LGTM 🎉
ffa3dab
to
17d4d01
Compare
This commit adds TestXXHandshake test which just ensures that the current handshake logic works correctly. The reason for adding this test now is so that we can use it to test a refactor too.
GBN reads an entire packet at once and so does not really care about the number of bytes that the caller is expecting to read. To allow the caller to read a payload byte by byte, we can use a bytes buffer which we will populate with the full gbn payload and then subsequent read calls will read from the buffer until it is empty.
17d4d01
to
4e6d8d8
Compare
Failing the linter rn:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excellent work!
Have always wanted to do such a refactor, but back then we didn't have any other handshakes we were using on the LN layer. Completed an initial pass, and have another queue'd up for tomorrow. Solid tests coverage, just have a few other things I want to examine more closely.
pk2, err := btcec.NewPrivateKey(btcec.S256()) | ||
require.NoError(t, err) | ||
|
||
// Create a password that will be used to mask the first ephemeral key. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems to have a lot of overlap with these tests? https://github.com/lightninglabs/lightning-node-connect/blob/master/mailbox/tcp_noise_test.go#L108
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this is from a slightly higher layer of abstraction though, the gRPC level.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah i wanted to write tests that actually use the ServerHandshake
and ClientHandshake
functions.
afaict, we dont use the code in tcp_noise_conn.go
and tcp_noise_listener.go
anywhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
afaict, we dont use the code in tcp_noise_conn.go and tcp_noise_listener.go anywhere?
Correct, but we can use them when we eventually add the pure TCP version of LNC, for nodes that don't really need the NAT traversal component.
@@ -298,19 +303,38 @@ type handshakeState struct { | |||
|
|||
remoteStatic *btcec.PublicKey // nolint | |||
remoteEphemeral *btcec.PublicKey // nolint | |||
|
|||
password []byte |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps this should live in something more PAKE specific?
Same comment re the payloads below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
meaning embed a new struct here? I would say only the password is PAKE specific? the payloads are part of any Noise handshake.
} | ||
|
||
protocolName := fmt.Sprintf( | ||
"Noise_%s_%s_%s_%s", pattern.Name, dhFn, cipherFn, hashFn, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to make sure we're not making a backwards incompatible change here, as this is used to generate the very first handshake digest.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah def. I have tested running a new client (which runs off the refactor) agains a server with the previous code and that works 👍
return fmt.Errorf("unknown act number: %d", mp.ActNum) | ||
} | ||
|
||
_, err := buff.Write(h.EncryptAndHash(payload)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Getting through the PR still, but marking here to ensure that the other party is actually able to read this information as is. As right now, I don't see the existing encrypted length prefix that we use (that includes a MAC) as normal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for version 0, currently there is a fixed 500 bytes for the Act 2 payload that must be written/read by both sides (see the ActTwoPayloadSize
variable on L395) and then we do write the encrypted length prefix on L404
mailbox/noise.go
Outdated
// the MessagePattern Tokens are processed and then any extra cipher text is | ||
// decrypted as defined by the handshake version. | ||
func (h *handshakeState) readMsgPattern(r io.Reader, mp MessagePattern) error { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Stray new line.
mailbox/noise.go
Outdated
for _, token := range tokens { | ||
switch token { | ||
case e: | ||
e, err := btcec.NewPrivateKey(btcec.S256()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We still want that ephemeralGen
function here, so we can do things like test vectors eventually and also make the tests more determinstic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok cool yeah that makes sense. Will add it back 👍
}, | ||
} | ||
|
||
// KKPattern represents the KK Noise pattern in which both initiator |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noice, also this works as both sides already know which mailbox ID to be expecting, so they know which keys to expect.
mailbox/noise_patterns.go
Outdated
me Token = "me" | ||
) | ||
|
||
// ActNum is the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Incomplete sentence.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
haha will fix 👍
btw, what are your thoughts on having this ActNum variable added to the message patterns in the first place? cause technically we can just get the number from the index of the message pattern in the handshake pattern. So this isnt strictly necessary... But just added it to make the code a bit more readable
Refactor the noise handshakestate code. This commit makes the code more reusable and takes advantage of the fact that the message pattern token writing and reading are completely separate from the payload writing and reading. With this commit, we also have all the cryto code necessary for when we add the `KK` pattern for the second handshake. A test is added for the KK pattern here too.
In this commit, the idea of a min supported and max supported handshake version is introduced so that client and server can negotiate which version they will use. The client will always send the minimum version they support in act 1. The server will then send its maximum supported version back in act 2. This is done due to the fact that for TW, the client will always be the first to upgrade versions. What ever the server sends back in act 2 is the version they will continue with. This commit also adds a unit test to test if a handshake is successfull given different version congigurations.
With handshake version 1, the auth data is sent in a dynamic field in act 2 to allow for large authdata.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the review @Roasbeef 🚀 updated 👍
pk2, err := btcec.NewPrivateKey(btcec.S256()) | ||
require.NoError(t, err) | ||
|
||
// Create a password that will be used to mask the first ephemeral key. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah i wanted to write tests that actually use the ServerHandshake
and ClientHandshake
functions.
afaict, we dont use the code in tcp_noise_conn.go
and tcp_noise_listener.go
anywhere?
return fmt.Errorf("unknown act number: %d", mp.ActNum) | ||
} | ||
|
||
_, err := buff.Write(h.EncryptAndHash(payload)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for version 0, currently there is a fixed 500 bytes for the Act 2 payload that must be written/read by both sides (see the ActTwoPayloadSize
variable on L395) and then we do write the encrypted length prefix on L404
mailbox/noise.go
Outdated
for _, token := range tokens { | ||
switch token { | ||
case e: | ||
e, err := btcec.NewPrivateKey(btcec.S256()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok cool yeah that makes sense. Will add it back 👍
mailbox/noise_patterns.go
Outdated
me Token = "me" | ||
) | ||
|
||
// ActNum is the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
haha will fix 👍
btw, what are your thoughts on having this ActNum variable added to the message patterns in the first place? cause technically we can just get the number from the index of the message pattern in the handshake pattern. So this isnt strictly necessary... But just added it to make the code a bit more readable
@@ -298,19 +303,38 @@ type handshakeState struct { | |||
|
|||
remoteStatic *btcec.PublicKey // nolint | |||
remoteEphemeral *btcec.PublicKey // nolint | |||
|
|||
password []byte |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
meaning embed a new struct here? I would say only the password is PAKE specific? the payloads are part of any Noise handshake.
} | ||
|
||
protocolName := fmt.Sprintf( | ||
"Noise_%s_%s_%s_%s", pattern.Name, dhFn, cipherFn, hashFn, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah def. I have tested running a new client (which runs off the refactor) agains a server with the previous code and that works 👍
4e6d8d8
to
4553a9b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 🍭
With the new handshake ( |
This PR does the following:
_KK
pattern handshake when the time comes (a test for this is added too).