2018-10-23 22:13:47 +00:00
|
|
|
(* (c) 2018 Hannes Mehnert, all rights reserved *)
|
|
|
|
|
2018-10-25 14:55:54 +00:00
|
|
|
open Rresult
|
2018-10-23 22:10:08 +00:00
|
|
|
open Rresult.R.Infix
|
2017-05-26 14:30:34 +00:00
|
|
|
|
2018-10-28 00:03:27 +00:00
|
|
|
(* we skip all non-albatross certificates *)
|
2018-10-28 19:50:10 +00:00
|
|
|
let cert_name cert =
|
|
|
|
match X509.Extension.unsupported cert Vmm_asn.oid with
|
|
|
|
| None -> None
|
|
|
|
| Some _ ->
|
|
|
|
let data = X509.common_name_to_string cert in
|
|
|
|
(* if the common name is empty, skip [useful for vmmc_bistro at least]
|
|
|
|
TODO: document properly and investigate potential security issue with
|
|
|
|
multi-tenant system (likely ca should ensure to never sign a delegation
|
|
|
|
with empty common name) *)
|
|
|
|
if data = "" then None else Some data
|
|
|
|
|
2018-10-28 00:03:27 +00:00
|
|
|
let name chain =
|
|
|
|
List.fold_left (fun acc cert ->
|
2018-10-28 19:50:10 +00:00
|
|
|
match cert_name cert with
|
2018-10-28 00:03:27 +00:00
|
|
|
| None -> acc
|
2018-10-28 19:50:10 +00:00
|
|
|
| Some data -> data :: acc)
|
2018-10-28 00:03:27 +00:00
|
|
|
[] chain
|
2018-10-25 14:55:54 +00:00
|
|
|
|
|
|
|
(* this separates the leaf and top-level certificate from the chain,
|
|
|
|
and also reverses the intermediates (to be (leaf, CA -> subCA -> subCA')
|
|
|
|
in which subCA' signed leaf *)
|
|
|
|
let separate_chain = function
|
|
|
|
| [] -> Error (`Msg "empty chain")
|
|
|
|
| [ leaf ] -> Ok (leaf, [])
|
|
|
|
| leaf :: xs -> Ok (leaf, List.rev xs)
|
|
|
|
|
|
|
|
let wire_command_of_cert version cert =
|
|
|
|
match X509.Extension.unsupported cert Vmm_asn.oid with
|
2018-10-28 19:50:10 +00:00
|
|
|
| None -> Error `Not_present
|
2018-10-25 14:55:54 +00:00
|
|
|
| Some (_, data) ->
|
2018-10-28 19:50:10 +00:00
|
|
|
match Vmm_asn.cert_extension_of_cstruct data with
|
|
|
|
| Error (`Msg p) -> Error (`Parse p)
|
|
|
|
| Ok (v, wire) ->
|
|
|
|
if not (Vmm_commands.version_eq v version) then
|
|
|
|
Error (`Version v)
|
|
|
|
else
|
|
|
|
Ok wire
|
2017-05-26 14:30:34 +00:00
|
|
|
|
2018-10-28 19:50:10 +00:00
|
|
|
let extract_policies version chain =
|
|
|
|
List.fold_left (fun acc cert ->
|
|
|
|
match acc, wire_command_of_cert version cert with
|
|
|
|
| Error e, _ -> Error e
|
|
|
|
| Ok acc, Error `Not_present -> Ok acc
|
|
|
|
| Ok _, Error (`Parse msg) -> Error (`Msg msg)
|
|
|
|
| Ok _, Error (`Version received) ->
|
|
|
|
R.error_msgf "unexpected version %a (expected %a)"
|
|
|
|
Vmm_commands.pp_version received
|
|
|
|
Vmm_commands.pp_version version
|
|
|
|
| Ok (prefix, acc), Ok (`Policy_cmd (`Policy_add p)) ->
|
|
|
|
let name = match cert_name cert with
|
|
|
|
| None -> prefix
|
|
|
|
| Some x -> x :: prefix
|
|
|
|
in
|
|
|
|
Ok (name, (name, p) :: acc)
|
|
|
|
| _, Ok wire ->
|
|
|
|
R.error_msgf "unexpected wire %a" Vmm_commands.pp wire)
|
|
|
|
(Ok ([], [])) chain
|
|
|
|
|
2018-10-23 22:10:08 +00:00
|
|
|
let handle _addr version chain =
|
2018-10-28 00:03:27 +00:00
|
|
|
separate_chain chain >>= fun (leaf, rest) ->
|
|
|
|
let name = name chain in
|
2018-10-23 22:10:08 +00:00
|
|
|
Logs.debug (fun m -> m "leaf is %s, chain %a"
|
|
|
|
(X509.common_name_to_string leaf)
|
|
|
|
Fmt.(list ~sep:(unit " -> ") string)
|
2018-10-28 00:03:27 +00:00
|
|
|
(List.map X509.common_name_to_string rest)) ;
|
2018-10-28 19:50:10 +00:00
|
|
|
extract_policies version rest >>= fun (_, policies) ->
|
2018-10-23 22:10:08 +00:00
|
|
|
(* TODO: logging let login_hdr, login_ev = Log.hdr name, `Login addr in *)
|
2018-10-28 19:50:10 +00:00
|
|
|
match wire_command_of_cert version leaf with
|
|
|
|
| Error (`Parse p) -> Error (`Msg p)
|
|
|
|
| Error (`Not_present) ->
|
|
|
|
Error (`Msg "leaf certificate does not contain an albatross extension")
|
|
|
|
| Error (`Version received) ->
|
|
|
|
R.error_msgf "unexpected version %a (expected %a)"
|
|
|
|
Vmm_commands.pp_version received
|
|
|
|
Vmm_commands.pp_version version
|
|
|
|
| Ok wire ->
|
|
|
|
(* we only allow some commands via certificate *)
|
|
|
|
match wire with
|
|
|
|
| `Console_cmd (`Console_subscribe _)
|
|
|
|
| `Stats_cmd `Stats_subscribe
|
|
|
|
| `Log_cmd (`Log_subscribe _)
|
|
|
|
| `Vm_cmd _
|
|
|
|
| `Policy_cmd `Policy_info -> Ok (name, policies, wire)
|
|
|
|
| _ -> Error (`Msg "unexpected command")
|