The DTLS 1.2 handshake looks like thus;
All of this is able to be encapsulated in Handshaker
objects, which handle all of this (+ retransmission) for the clients.
Because of this, handshakes have a special API which makes them able to alert the program to wait until a certain moment to retransmit the packets they'd want to send.
However, the 6th flight could get lost, either the CCS or the Finished packet, which means the client can get in a deadlock, see the following passage from [RFC6347];
In addition, for at least twice the default MSL defined for [TCP],
when in the FINISHED state, the node that transmits the last flight
(the server in an ordinary handshake or the client in a resumed
handshake) MUST respond to a retransmit of the peer's last flight
with a retransmit of the last flight. This avoids deadlock
conditions if the last flight gets lost.
However, this would block the server handshaker from transitioning into a connection object until the client has sent any application data.
It would be more "correct" to wait until a client sends data, but depending on the application, the server might want to immediately start to send data.
This could be especially problematic with resuming sessions, or #9, which might require this kind of "last state" to be certain before either side starts sending buffered data again.
For now, I think it's more clean to wait for application data, but in the future I could add a "server handshaker mode" which immediately transitions to a connection object after finishing the last flight, but keeps it sealed and keeps it ready to be sent if the client were to send flight 5 again, this would be a ton of extra logic to keep, though.