<commit_before>open Nocrypto

open Utils

open Core
open State
open Handshake_common
open Config

let (<+>) = Cs.(<+>)

let hello_request state =
  if state.config.use_reneg then
    let hr = HelloRequest in
    Tracing.sexpf ~tag:"handshake-out" ~f:sexp_of_tls_handshake hr ;
    let state = { state with machina = Server AwaitClientHelloRenegotiate } in
    return (state, [`Record (Packet.HANDSHAKE, Writer.assemble_handshake hr)])
  else
    fail_handshake


let answer_client_finished state session client_fin raw log =
  let client, server =
    let checksum = Handshake_crypto.finished state.protocol_version session.master_secret in
    (checksum "client finished" log, checksum "server finished" (log @ [raw]))
  in
  assure (Cs.equal client client_fin)
  >>= fun () ->
  let fin = Finished server in
  let fin_raw = Writer.assemble_handshake fin in
  (* we really do not want to have any leftover handshake fragments *)
  assure (Cs.null state.hs_fragment)
  >|= fun () ->
  let session = { session with renegotiation = (client, server) }
  and machina = Server Established
  in
  Tracing.sexpf ~tag:"handshake-out" ~f:sexp_of_tls_handshake fin ;
  ({ state with machina ; session = session :: state.session },
   [`Record (Packet.HANDSHAKE, fin_raw)])

let establish_master_secret state session premastersecret raw log =
  let client_ctx, server_ctx, master_secret =
    Handshake_crypto.initialise_crypto_ctx state.protocol_version session premastersecret
  in
  let session = { session with master_secret = master_secret } in
  let machina =
    match session.peer_certificate with
    | [] -> AwaitClientChangeCipherSpec (session, server_ctx, client_ctx, log @ [raw])
    | _ -> AwaitClientCertificateVerify (session, server_ctx, client_ctx, log @ [raw])
  in
  Tracing.cs ~tag:"master-secret" master_secret ;
  ({ state with machina = Server machina }, [])

let private_key session =
  match session.own_private_key with
    | Some priv -> return priv
    | None      -> fail_handshake

let validate_certs certs authenticator session =
  match certs with
  | [] ->
    return session
  | cs ->
    validate_chain authenticator cs None `RSA `Digital_signature >|= fun ((cert, cs), trust_anchor) ->
    { session with peer_certificate = cert :: cs ; trust_anchor }

let answer_client_certificate_RSA state session certs raw log =
  validate_certs certs state.config.authenticator session >|= fun session ->
  let machina = AwaitClientKeyExchange_RSA (session, log @ [raw]) in
  ({ state with machina = Server machina }, [])

let answer_client_certificate_DHE_RSA state session dh_sent certs raw log =
  validate_certs certs state.config.authenticator session >|= fun session ->
  let machina = AwaitClientKeyExchange_DHE_RSA (session, dh_sent, log @ [raw]) in
  ({ state with machina = Server machina }, [])

let answer_client_certificate_verify state session sctx cctx verify raw log =
  let sigdata = Cs.appends log in
  verify_digitally_signed state.protocol_version verify sigdata session.peer_certificate >|= fun () ->
  let machina = AwaitClientChangeCipherSpec (session, sctx, cctx, log @ [raw]) in
  ({ state with machina = Server machina }, [])

let answer_client_key_exchange_RSA state session kex raw log =
  (* due to bleichenbacher attach, we should use a random pms *)
  (* then we do not leak any decryption or padding errors! *)<commit_msg>validate certificates when a certificate message is received, also if the certificate list is empty.<commit_after>open Nocrypto

open Utils

open Core
open State
open Handshake_common
open Config

let (<+>) = Cs.(<+>)

let hello_request state =
  if state.config.use_reneg then
    let hr = HelloRequest in
    Tracing.sexpf ~tag:"handshake-out" ~f:sexp_of_tls_handshake hr ;
    let state = { state with machina = Server AwaitClientHelloRenegotiate } in
    return (state, [`Record (Packet.HANDSHAKE, Writer.assemble_handshake hr)])
  else
    fail_handshake


let answer_client_finished state session client_fin raw log =
  let client, server =
    let checksum = Handshake_crypto.finished state.protocol_version session.master_secret in
    (checksum "client finished" log, checksum "server finished" (log @ [raw]))
  in
  assure (Cs.equal client client_fin)
  >>= fun () ->
  let fin = Finished server in
  let fin_raw = Writer.assemble_handshake fin in
  (* we really do not want to have any leftover handshake fragments *)
  assure (Cs.null state.hs_fragment)
  >|= fun () ->
  let session = { session with renegotiation = (client, server) }
  and machina = Server Established
  in
  Tracing.sexpf ~tag:"handshake-out" ~f:sexp_of_tls_handshake fin ;
  ({ state with machina ; session = session :: state.session },
   [`Record (Packet.HANDSHAKE, fin_raw)])

let establish_master_secret state session premastersecret raw log =
  let client_ctx, server_ctx, master_secret =
    Handshake_crypto.initialise_crypto_ctx state.protocol_version session premastersecret
  in
  let session = { session with master_secret = master_secret } in
  let machina =
    match session.peer_certificate with
    | [] -> AwaitClientChangeCipherSpec (session, server_ctx, client_ctx, log @ [raw])
    | _ -> AwaitClientCertificateVerify (session, server_ctx, client_ctx, log @ [raw])
  in
  Tracing.cs ~tag:"master-secret" master_secret ;
  ({ state with machina = Server machina }, [])

let private_key session =
  match session.own_private_key with
    | Some priv -> return priv
    | None      -> fail_handshake

let validate_certs certs authenticator session =
  validate_chain authenticator certs None `RSA `Digital_signature >|= fun ((cert, cs), trust_anchor) ->
  { session with peer_certificate = cert :: cs ; trust_anchor }

let answer_client_certificate_RSA state session certs raw log =
  validate_certs certs state.config.authenticator session >|= fun session ->
  let machina = AwaitClientKeyExchange_RSA (session, log @ [raw]) in
  ({ state with machina = Server machina }, [])

let answer_client_certificate_DHE_RSA state session dh_sent certs raw log =
  validate_certs certs state.config.authenticator session >|= fun session ->
  let machina = AwaitClientKeyExchange_DHE_RSA (session, dh_sent, log @ [raw]) in
  ({ state with machina = Server machina }, [])

let answer_client_certificate_verify state session sctx cctx verify raw log =
  let sigdata = Cs.appends log in
  verify_digitally_signed state.protocol_version verify sigdata session.peer_certificate >|= fun () ->
  let machina = AwaitClientChangeCipherSpec (session, sctx, cctx, log @ [raw]) in
  ({ state with machina = Server machina }, [])

let answer_client_key_exchange_RSA state session kex raw log =
  (* due to bleichenbacher attach, we should use a random pms *)
  (* then we do not leak any decryption or padding errors! *)
{'fraction_non_alphanumeric': 0.08720070942950044, 'fraction_numerical': 0.0, 'mean_word_length': 4.3578780680918445, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1842236', 'n_tokens_mistral': 2086, 'n_tokens_neox': 2030, 'n_words': 660}