Skip to content
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

How to config a server with the most simple handshake? #389

Closed
swechencheng opened this issue Aug 5, 2021 · 14 comments · Fixed by #636
Closed

How to config a server with the most simple handshake? #389

swechencheng opened this issue Aug 5, 2021 · 14 comments · Fixed by #636

Comments

@swechencheng
Copy link

Summary

Is it possible to config a server using PSK with the most simple flow?

Motivation

I'm trying to follow what is described here:
https://docs.oracle.com/en/java/javase/16/security/transport-layer-security-tls-protocol-overview.html#GUID-F1BFB231-BE35-4B14-BB8D-7F33D31A117D

dtls-handshake

I just want to config the server to exclude all the optional part, so no certificate, no key exchange, no signature.
Is it possible to do so? If yes, how?

Thanks!

@daenney
Copy link
Member

daenney commented Aug 5, 2021

Take a look at https://github.com/pion/dtls/blob/master/examples/listen/psk/main.go. I think that's what you want? Configurability wise, whatever nobs exist on dtls.Config you can use.

@swechencheng
Copy link
Author

Yeah, I am trying with that. But how to get rid of ServerKeyExchange or simply get rid of Certificate when using PSK? As Certificate is indicated as optional in the graph.

@daenney
Copy link
Member

daenney commented Aug 5, 2021

Certificates aren't used if you configure PSK.

@swechencheng
Copy link
Author

But the documentation says:

	// Certificates contains certificate chain to present to the other side of the connection.
	// Server MUST set this if PSK is non-nil
	// client SHOULD sets this so CertificateRequests can be handled if PSK is non-nil
	Certificates []tls.Certificate

which makes me confused...

@daenney
Copy link
Member

daenney commented Aug 5, 2021

I think that's a typo in the docs. I believe it should be "Servers MUST set this if PSK is nil". Just don't set it in your dtls.Config.

Also, if you want to verify what happens, wireshark is your friend.

@swechencheng
Copy link
Author

Well, actually I am running a coap server.
But my client which uses tinydtls still complains that it receive a received handshake packet of type: server_key_exchange (12) but it is not designed to handle that.
So the coap server is not giving any Certificates but it still seems to require that:
https://github.com/plgd-dev/go-coap/blob/9b9018ae0577d6c64733622554a1fd870f0e6777/examples/dtls/psk/server/main.go#L56

@daenney
Copy link
Member

daenney commented Aug 5, 2021

Interesting. So that seems to happen due to

handshakeCachePullRule{handshake.TypeServerKeyExchange, cfg.initialEpoch, false, true},
most likely. I believe that should be conditional on a PSK client identity hint being set, and if it's not we should be skipping the server key exchange.

I'm not 100% sure on that, so finding some actual RFCs that state what's supposed to happen here would be good.

@swechencheng
Copy link
Author

BTW, when I am looking some other implementation like Californium:
https://github.com/GoogleCloudPlatform/community/blob/70507b2ac25d214c91d62b14102e9047b184225f/tutorials/cloud-iot-coap-proxy/proxy/src/main/java/com/agosto/iot/CredentialsUtil.java#L151
Their server is using something called pskIdentity, is that the same as PSKIdentityHint that your dtls lib uses?

@daenney
Copy link
Member

daenney commented Aug 5, 2021

Yeah, it's a bit confusingly named. But basically the "hint" is provided by the server, to help the client pick an identity. The client can set a specific identity. We're just reusing the same field, which we might be better off not doing to make this a bit clearer.

I don't think our implementation will actually work if you set a PSK but don't set an identity, based on

dtls/conn.go

Line 257 in 2e643d9

case config.PSK != nil && config.PSKIdentityHint == nil:

That feels wrong. Should be fine for the client to never pick an identity, even if the server gave it a hint. Though you can always set something, it's harmless if the server doesn't care about it I think 😕.

@daenney
Copy link
Member

daenney commented Aug 5, 2021

If you can modify the code locally, I'd say try and see what happens if you make a change like this in flight3handler.go:

if cfg.localPSKCallback != nil {
  flights := []handshakeCachePullRule{
    handshakeCachePullRule{handshake.TypeServerHello, cfg.initialEpoch, false, false},
  }

  if len(cfg.localPSKIdentityHint) > 0 {
        flights = append(flights, handshakeCachePullRule{handshake.TypeServerKeyExchange, cfg.initialEpoch, false, true})
  }

  flights = append(flights, handshakeCachePullRule{handshake.TypeServerHelloDone, cfg.initialEpoch, false, false})
  seq, msgs, ok = cache.fullPullMap(flights...)
}

That should fix it to work as expected as a server. Just make sure to not set dtls.Config.PSKIdentityHint.

@swechencheng
Copy link
Author

Tested and it works!
Just a syntax fix needed:

seq, msgs, ok = cache.fullPullMap(state.handshakeRecvSequence, flights...)

@daenney Tack så mycket! Would you make a PR for this or?

@daenney
Copy link
Member

daenney commented Aug 6, 2021

I'll take a look at that. I need to make sure we can always elide the ServerKeyExchange in the PSK scenario this way. I suspect there might be other properties that if set even with PSK we should still send ServerKeyExchange even if the identity is null.

I'll need to dig into the RFCs and hope something spells this out, b/c right now I cribbed this trick based on a paragraph in OpenSSL docs.

@Sean-Der You seem to have a knack for knowing these things. Any chance you can chime in?

@swechencheng
Copy link
Author

swechencheng commented Aug 20, 2021

Hi again,
One thing I have observed from our old java implementation based on Eclipse Californium is that the server use "flight 4" to handle the same DTLS client handshake hello I used above:

Aug 20 13:31:51 Parsing HANDSHAKE message without a session
Aug 20 13:31:52 Parsing HANDSHAKE message without a session
Aug 20 13:31:52 connection: add CID=88E7A0A6C864 (size 3)
Aug 20 13:31:52 connection: CID=88E7A0A6C864 - /fd00:e859:ff00:0:212:4b00:1e1b:3e62:61616 added! CID=0F2F63B09269 removed from address.
Aug 20 13:31:52 Setting MTU for peer [/fd00:e859:ff00:0:212:4b00:1e1b:3e62:61616] to 1500 bytes
Aug 20 13:31:52 Setting maximum fragment length for peer [/fd00:e859:ff00:0:212:4b00:1e1b:3e62:61616] to 1411 bytes
Aug 20 13:31:52 Processing CLIENT_HELLO (1) message from peer [/fd00:e859:ff00:0:212:4b00:1e1b:3e62:61616], seqn: [1]
Aug 20 13:31:52 handshake started dtls-con: CID=88E7A0A6C864, /fd00:e859:ff00:0:212:4b00:1e1b:3e62:61616, is alive
Aug 20 13:31:52 Handshake with [/fd00:e859:ff00:0:212:4b00:1e1b:3e62:61616] has been started
Aug 20 13:31:52 Negotiated cipher suite [TLS_PSK_WITH_AES_128_CCM_8] with peer [/fd00:e859:ff00:0:212:4b00:1e1b:3e62:61616]
Aug 20 13:31:52 Processed CLIENT_HELLO (1) message from peer [/fd00:e859:ff00:0:212:4b00:1e1b:3e62:61616]
Aug 20 13:31:52 Updated receive window with sequence number [1]: new upper boundary [1], new bit vector [10]
Aug 20 13:31:52 Parsing HANDSHAKE message plaintext with parameter [KeyExgAl=PSK, cert.type=X_509]
Aug 20 13:31:52 response for flight 4 started
Aug 20 13:31:52 Processing CLIENT_KEY_EXCHANGE (16) message from peer [/fd00:e859:ff00:0:212:4b00:1e1b:3e62:61616], seqn: [2]
Aug 20 13:31:52 client [/fd00:e859:ff00:0:212:4b00:1e1b:3e62:61616] uses PSK identity [XgJQ]
Aug 20 13:31:52 Processed CLIENT_KEY_EXCHANGE (16) message from peer [/fd00:e859:ff00:0:212:4b00:1e1b:3e62:61616]
Aug 20 13:31:52 Updated receive window with sequence number [2]: new upper boundary [2], new bit vector [110]
Aug 20 13:31:52 Processing Change Cipher Spec (20) message from peer [/fd00:e859:ff00:0:212:4b00:1e1b:3e62:61616]
Aug 20 13:31:52 Processed Change Cipher Spec (20) message from peer [/fd00:e859:ff00:0:212:4b00:1e1b:3e62:61616]
Aug 20 13:31:53 Parsing HANDSHAKE message plaintext with parameter [KeyExgAl=PSK, cert.type=X_509]
Aug 20 13:31:53 response for flight 4 started
Aug 20 13:31:53 Processing FINISHED (20) message from peer [/fd00:e859:ff00:0:212:4b00:1e1b:3e62:61616], seqn: [3]
Aug 20 13:31:53 Setting maximum fragment length for peer [/fd00:e859:ff00:0:212:4b00:1e1b:3e62:61616] to 1395 bytes
Aug 20 13:31:53 session established dtls-con: CID=88E7A0A6C864, /fd00:e859:ff00:0:212:4b00:1e1b:3e62:61616, ongoing handshake 581C5FD16E69, is alive
Aug 20 13:31:53 Session with [/fd00:e859:ff00:0:212:4b00:1e1b:3e62:61616] has been established
Aug 20 13:31:53 Processed FINISHED (20) message from peer [/fd00:e859:ff00:0:212:4b00:1e1b:3e62:61616]
Aug 20 13:31:53 Updated receive window with sequence number [0]: new upper boundary [0], new bit vector [1]
Aug 20 13:31:55 Updated receive window with sequence number [1]: new upper boundary [1], new bit vector [11]
Aug 20 13:31:55 Handshake with [/fd00:e859:ff00:0:212:4b00:1e1b:3e62:61616] has been completed
Aug 20 13:31:55 handshake completed dtls-con: CID=88E7A0A6C864, /fd00:e859:ff00:0:212:4b00:1e1b:3e62:61616, session established 581C5FD16E69, is alive

Why it is flight 4 in Californium? And why we are using flight 3 in your library? What's the difference?
From the RFC document I realize that flight 3 is on the client side and flight 4 is on the server side. So is your flight3handler actually handles flight 3 and do flight 4?
Thanks!

Sean-Der pushed a commit that referenced this issue May 31, 2024
Assert that ServerKeyExchange is only sent with PSKIdentityHint is set
on the server side.

Resolves #389
Sean-Der pushed a commit that referenced this issue May 31, 2024
Assert that ServerKeyExchange is only sent with PSKIdentityHint is set
on the server side.

Resolves #389
@Sean-Der
Copy link
Member

Sean-Der commented May 31, 2024

Two things that need to be fixed here

  • Support Client with no Identity. I confirmed with OpenSSL that it can be 0, but the attribute must still be sent. We support this if you do a IdentityHint of []byte{}. I also added a test to confirm this behavior.
  • Support Servers with no Identity. We do this today, but no test exists

Sean-Der pushed a commit that referenced this issue May 31, 2024
* Assert that ServerKeyExchange is only sent with PSKIdentityHint is set
  on the server side.
* Assert that a empty PSKIdentityHint can be used for clients.

Resolves #389
Sean-Der pushed a commit that referenced this issue May 31, 2024
* Assert that ServerKeyExchange is only sent with PSKIdentityHint is set
  on the server side.
* Assert that a empty PSKIdentityHint can be used for clients.

Resolves #389
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants