-
Notifications
You must be signed in to change notification settings - Fork 9
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
Retrieve long term static key for Conn #4
Conversation
noise/conn.go
Outdated
@@ -319,6 +320,9 @@ ContinueHandshake: | |||
if !c.config.PublicKeyVerifier(hs.rs.PublicKey[:], receivedPayload) { | |||
return errors.New("Noise: the received public key could not be authenticated") | |||
} | |||
c.isRemoteAuthenticated = true |
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.
good point, I was toying with this idea of having a isRemoteAuthenticated
value you can check.
I'm not sure it is useful as the handshake you're using should make it pretty clear that you're authenticating the remote, but I thought it could be "useful" as a defense-in-depth mechanism. What do you think?
It should also probably be exported if it's meant to be used by developers.
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 put it there because I used the IsAuthenticated
method in StaticKey
. If it's not really needed (see comment below) then we can totally drop that.
In my opinion, the semantic of IsAuthenticated
is a bit vague or redundant: do you mean authenticated with a longterm static key ? Because users of that library must intentionally declare the pattern they want to use and if the handshake succeeds and a static key must have been authenticated in some way, then it is by default Authenticated
no ?
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.
authenticated with a longterm static key?
not necessarily, I am trying to get back into the state of mind I had when I wrote this. But I think I wanted to create an out-of-band authentication. For example something like Noise_NN where you would extract a fingerprint and authenticate the connection post-handshake. Noise_NNoob maybe? Although I'm not sure it deserves a name. By having this isRemoteAuthenticated
you can check if peers have actually verified the fingerprint. You can think of some application that would want to show some features only if this var been set.
noise/conn.go
Outdated
@@ -17,6 +17,7 @@ type Conn struct { | |||
// handshake | |||
config *Config // configuration passed to constructor | |||
hs handshakeState | |||
remotePub []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.
why not making it a [32]byte
to avoid having to make
during the handshake?
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.
Becase I wanted to see if you can see it ? ahah. well spotted.
noise/conn.go
Outdated
// StaticKey returns the static key of the remote peer. It is useful in case the | ||
// static key is only transmitted during the handshake. | ||
func (c *Conn) StaticKey() ([]byte, error) { | ||
if !c.IsRemoteAuthenticated() { |
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.
Are there usecases where you would still want to obtain the public key, even if the peer has not been authenticated yet? Maybe if you're planning to authenticate post-handshake (using a short-authentication string or something like that)
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.
True. I was not sure about that, so I just thought going to the safest path. But Is it really possible to get the static key without verifying ? This library panics if there's no PublicKeyVerifier
in the Config
IIRC .
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.
true.
Another scenario I can think of: setting up the PublicKeyVerifier()
based on the static public key you received. But this is currently not possible with this library.
noise/conn.go
Outdated
if !c.IsRemoteAuthenticated() { | ||
return nil, errors.New("noise: remote peer not authenticated") | ||
} | ||
if !c.handshakeComplete { |
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.
is it important that the handshake has to be finished?
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.
Mhhhh I wanna make sure that the key I get when calling StaticKey
is the right one (i.e. verified by PublicKeyVerifier
). Maybe it is possible to deliver it before the handshake completely finishes, but in my use case, I'm fine with waiting the handshake to be finished so I'm sure.
In any case, looking at the code where the PublicKeyVerifier
gets called, it's almost at the end of the Handshake
method so not even sure what we can do "earlier".
noise/conn.go
Outdated
@@ -319,6 +320,9 @@ ContinueHandshake: | |||
if !c.config.PublicKeyVerifier(hs.rs.PublicKey[:], receivedPayload) { | |||
return errors.New("Noise: the received public key could not be authenticated") | |||
} | |||
c.isRemoteAuthenticated = true | |||
c.remotePub = make([]byte, 32) | |||
copy(c.remotePub, hs.rs.PublicKey[:]) |
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.
shouldn't you do this when receiving the s
token?
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.
See comment above. I just want to get the static key when it has been verified.
BTW, It is possible also to retrieve the value directly from the PublicKeyVerifier
but having a StaticKey
method is more practical code-wise.
Hey Nicolas! Glad to see you ended up here from rwc :) I posted some comments on your PR, I'm looking forward hearing your thoughts on these. |
noise/conn.go
Outdated
if c.remotePub == nil { | ||
return nil, errors.New("noise: no remote static key given") | ||
} | ||
return c.remotePub, nil |
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.
why not returning hs.rs.PublicKey
instead? This way you wouldn't have to create a c.remotePub
and copy the public key into it.
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.
Because the hs.rs
is cleared when the handshake completes (c.hs.clear()
) and the clearing clears up also the public key. I think it could be relaxed to only clear up the private key but better be safe than sorry.
I've removed the whole |
Avec un ptit test en plus c'est mieux :) |
noise/conn.go
Outdated
@@ -17,6 +17,8 @@ type Conn struct { | |||
// handshake | |||
config *Config // configuration passed to constructor | |||
hs handshakeState | |||
remotePub [32]byte // remote static public 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.
Because the hs.rs is cleared when the handshake completes (c.hs.clear()) and the clearing clears up also the public key. I think it could be relaxed to only clear up the private key but better be safe than sorry.
So. Can we think of good reasons for clear()
to clear the public keys? If not, I'd rather have us modify the behavior of clear()
rather than adding new fields here :o
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 reasons to clear a key from memory is to avoid an attacker being able to read it (either because he's on the same machine or by using heartbleed style attacks, etc). Usually we clear a private key because that's what is most urgent to keep secret.
In a far far fetched scenario, we might also want to clear up the static public key to be able to deny later that we were participating in the communication ? (if we load the key via Yubikey on a computer which got compromised just after we used it so it still has the memory kept ? )
Lol this seems way too far fetched from me. So if you also can't find a realistic scenario, then let me know and I'll modify clear()
so it only clears the private 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'm not particularly interested in the deniability property which Noise doesn't provide in any case. I think a better idea would be to stop clear()
from removing the public keys. If you can make this change I'll accept your PR! Thanks again for the initial PR and the changes :) you rock
Switching to english because people might read us here ;) And sorry, one last comment on your PR :) I'm gonna look at Travis, good idea. |
Alright, added Travis! Thanks for the suggestion. |
Turns out it also raises some questions about the way you use struct vs pointers. If I don't copy the static key, in (Just try to remove the hs.clear() and my "copy" to see what I'm talking about if it's not clear) |
See the latest commit to see if that's ok with you. |
Hey! Sorry for the delay, I've been pretty busy lately, will get to review this shortly :) |
Good catch with the
I've been trying to avoid pointers where I think it does not optimize the code that much and provides more confusion vs simply using values. (I think the Go blog has a blogpost on this, which is why I do it.) But if you think there are places in the code where it would be better to use pointers, submit a PR :) Anyway this looks good to me, I'll probably think of just doing operations on Thanks for that awesome PR! (and for the discussions) |
I'm trying to port this to https://github.com/mimoo/disco if you find that interesting take a look, I've:
How do you use this function with the standard In addition I've added a |
@mimoo cool, looks like you're progressing well ! Unfortunately, my project is on a hold for some time at the moment.. I'll definitely have a look at disco when I'll take it up again. |
Hi David!
It's Nicolas, working at EPFL, we met @RWC18.
Thank you for this library, especially the
net.Conn
interface, that's what made me change to go here ;)However, with this PR, I'd like to add the possiblity of getting the static key which is sent during a handshake after the handshake's completed. It's especially useful on the server side (listening side) when all static keys are known, which peer contacted us.
I hope it's still correct. Especially the
isAuthenticated = true
, it may not be necessary but I was thinking that it should be there..Looking forwards to your comments !