-
-
Notifications
You must be signed in to change notification settings - Fork 10.1k
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
What do SSL_get_finished/SSL_get_peer_finished return? #5509
Comments
This is what is currently in ssl.h:
|
@kroeckx Is there any information on what a “Finished” message contains and/or how a program could meaningfully use it? |
The CHANGES files mentions:
|
Great, thank you a lot! This sounds like something we could almost directly carry over into our own documentation. (/cc @codedot) (I guess I could have come up with the idea of looking up why these methods were added in the first place myself… well, next time.) |
I guess we would also like to properly document that function, so a pull request is always welcome. |
As clear from the pull requests you pointed to, this can be used for tls-unique channel binding from rfc5929 |
There are probably betters ways to do channel-binding, although I forget which PR has it. Look for secret-exporter maybe? @addaleax you should push back on your requestor and ask what they want to do. There might be a better API for it. |
@richsalz The requester wants this for Ripple, where apparently usage of the Finished messages is built into the protocol. :( |
Wow, what a mess.
|
@richsalz, I know this is a somewhat ancient thread and I hate to resurrect the dead, but in the interest of improving our code and cleaning up the "mess" I am going to give it a shot. I am curious to know how you'd go about ensuring that two endpoints A and B can determine that they are talking directly to each other through one SSL session and not across two SSL connections that are intermediated by a proxy. You have several restrictions, but of particular interest are that:
In our case, each endpoint has a public/private keypair (the node identity). For our purposes, what we want is to know the identity of the other endpoint and to know that we are talking directly to that endpoint. Our solution: In the initial phases of a connection, each side independently calculates a "cookie" shared with the other side (derived by independently hashing both finished messages with SHA512, and then XORing the two values together) and signs the resulting hash with its node identity. The result: each endpoint knows the node identity of the other endpoint and is guaranteed that the SSL link is direct and not intermediated across two sessions through a proxy. Proxies that simply shuffle around encrypted packets aren't a concern in this scenario. Would your recommendation be to skip the complicated "cookie" calculation and use |
Treat the TLS connection as an authenticated, DH-style connection. Then do the key exchange as your first application-level messages. |
Thanks for the reply, @richsalz. I guess I'm not following because, in essence, that is exaclty what we do. Once the TLS connection is up, one of the two endpoints issues an For example:
I assume you take exception with the data that we sign which we derive from the finished messages by "reaching inside" the SSL session and pulling that data out. There's a reason for that: we need something that isn't under the sole control of either of the endpoints, since it's essential that the value being signed be random and not under the control of either party (coercing someone to sign an arbitrary value is bad). We could achieve this by having each side pick a random 256-bit value and then passing it to the other end; each endpoint would, then, combine the two values using XOR in a deterministic way and sign the result. But that would require the addition of at least two additional messages after the HTTP upgrade is negotiated. I'll grant you that that's not a huge burden. But even if we were willing to do that, there's still something else to consider: this solution would be vulnerable to an attack: an attacker could convince us both we're talking directly to each other when we are, in reality, talking through him over two independent TLS connections: it's an almost classic "triple handshake" attack. Using the TLS connection state effectively mitigates this scenario, strongly binds the TLS connection to its and eliminates the need for sending additional messages and complicating an already complex codebase. I don't mean to be difficult and I'm happy to redesign this scheme, but I'll need a little more than just "wow, what a mess." |
Sorry if I offended you, but reaching inside the protocol to extra data is not a good idea unless you own the protocol implementation. And I did give more suggestions, as did Kurt. Here's more details: make the node identity an X25519 keypair, and do a X25519 key exchange at the application layer. Look at channel bindings. You have, I think, designed yourself into a box. The only way to avoid an active MitM attack is to have authentication at least on the server side, and your requirements reject the common way (X509 certs and WebPKI) of doing that. |
I wasn't offended. I genuinely want to understand your concerns and to come up with a way to address them and I do appreciate your responses. I'm not arrogant or self-conceited enough to believe I have all the answers, and I do very much welcome feedback, especially from a subject matter expert, such as yourself.
I generally agree with you, although I guess what one does with the data matters. If I was, say, parsing the finished messages myself or somesuch, that would be bad.
The node identity already is a secp256k1 keypair. The whole point of this scheme is to strongly "bind" the SSL session to the secp256k1 keypairs each endpoint claims to have, which, in turn ensures that given two endpoints A and B, both A and B can be sure that the TLS link is directly between each other and not via a third party C with independent TLS sessions A <-> C <-> B. I agree that this scheme doesn't prevent a MITM attack in the general and broadest sense, but it does mean that each endpoints knows what the node identity of the other side is. This means that C can't convince A he's talking directly to B, or vice versa. And I hope you'll agree that that is, in itself, useful. I can't think of a way to do this purely at the "application layer" (i.e. without reaching into the TLS session and getting some data out of it) especially given the restrictions we have (can't mandate certificates, for example). If there's a "standard" way for us to get the benefits of the current scheme considering the restrictions we're operating under, I'm all over it and I'll code it up today. If the answer is tls-unique (at least as outlined in RFC-5929) then I have some concerns, but maybe that's not the latest-and-greatest. |
A couple of thoughts:
good luck. |
Even with TLS encrypted connections, it is possible for a determined attacker to mount certain types of relatively easy man-in-the-middle attacks which, if successful, could allow an attacker to tamper with messages exchanged between endpoints. The risk can be mitigated if each side has a certificate issued by a CA that the other side trusts. In the context of a decentralized and permissionless network, this is neither reasonable nor desirable. To prevent this problem all we need is to allow the two endpoints, A and B, to be able to independently verify that they are connected to each other over a single end-to-end TLS session, instead of separate TLS sessions which the attacker bridges. The protocol level handshake implements this security check by using digital signatures: each endpoint derives a fingerprint from the TLS session, which it signs with the private key associated with its own node identity. This strongly binds the TLS session to the identities of the two endpoints of the session. This commit introduces a new fingerprint derivation that uses modern and standardized TLS exporter functionality, instead of the existing derivation whch uses OpenSSL APIs that are non-standard, and derives different "incoming" and "outgoing" security cookies. Lastly, this commit refines the "self-connection" check to allow for the detection of accidental instances of node identity sharing. This check was first introduced with #4195 but was partially reverted due to a bug with #4438. By using distinct security cookies for incoming and outgoing connections, an attacker is no longer able to claim the identity of its peer by echoing its security cookie. The change is backwards compatible and servers with this commit will still generate and verify old-style fingerprints, in addition to the new style fingerprints. For a fuller discussion on this topic, please see: openssl/openssl#5509 XRPLF/rippled#2413 This commit was previously introduced as #3929, which was closed. If merged, it also fixes #2413 (which had been closed as a 'WONTFIX').
Hi! I’m opening an issue because there is a pull request to expose these two functions, which are public OpenSSL API (afaict), in Node.js.
There is almost no documentation on what the contents of the returned data are, or what guarantees could be made about them. They seem to be used in real-world applications, though.
Could anybody help with explaining? Even hints for where to start looking would be appreciated a lot.
The text was updated successfully, but these errors were encountered: