// The TLS 1.3 server handshake state machine (RFC 8446 Appendix A.2). A server receives
// the ClientHello, negotiates and sends its whole flight (ServerHello, EncryptedExten-
// sions, an optional CertificateRequest, Certificate, CertificateVerify, Finished), then
// waits for the client's second flight: the client Certificate and CertificateVerify
// when client authentication was requested, and finally the client Finished. This models
// the full-handshake, certificate-authenticated path a mooncat server drives.

///|
/// A server's handshake state (RFC 8446 A.2).
pub(all) enum TlsServerState {
  Start
  RecvdClientHello
  WaitCert
  WaitCertVerify
  WaitFinished
  Connected
} derive(Eq, Debug)

///|
/// The initial state, awaiting the ClientHello.
pub fn TlsServerState::new() -> TlsServerState {
  Start
}

///|
/// The ClientHello handshake type (RFC 8446 ยง4), which the shared constants omit.
let tls_hs_client_hello : Int = 1

///|
/// The next server state on receiving a handshake message of `msg_type` (RFC 8446 A.2):
/// the ClientHello that opens the handshake, then the client's Certificate,
/// CertificateVerify, and Finished. An out-of-order message is an unexpected-message
/// error.
pub fn tls_server_recv(
  state : TlsServerState,
  msg_type : Int,
) -> TlsServerState raise StreamStateError {
  match (state, msg_type) {
    (Start, t) if t == tls_hs_client_hello => RecvdClientHello
    (WaitCert, t) if t == tls_hs_certificate => WaitCertVerify
    (WaitCertVerify, t) if t == tls_hs_certificate_verify => WaitFinished
    (WaitFinished, t) if t == tls_hs_finished => Connected
    _ => raise StreamStateError("unexpected TLS 1.3 handshake message (server)")
  }
}

///|
/// The server's own action after receiving the ClientHello: it negotiates and sends its
/// whole flight, then waits for the client's Certificate (when `request_client_cert` is
/// set) or straight for the client Finished. Sending the flight in any other state is an
/// error.
pub fn tls_server_send_flight(
  state : TlsServerState,
  request_client_cert : Bool,
) -> TlsServerState raise StreamStateError {
  match state {
    RecvdClientHello =>
      if request_client_cert {
        WaitCert
      } else {
        WaitFinished
      }
    _ =>
      raise StreamStateError(
        "server may only send its flight after ClientHello",
      )
  }
}