2017-05-26 14:30:34 +00:00
|
|
|
(* (c) 2017 Hannes Mehnert, all rights reserved *)
|
|
|
|
|
|
|
|
open Vmm_provision
|
|
|
|
|
|
|
|
open Astring
|
|
|
|
|
|
|
|
open Rresult.R.Infix
|
|
|
|
|
2018-10-22 23:48:24 +00:00
|
|
|
|
|
|
|
let parse_db lines =
|
|
|
|
List.fold_left (fun acc s ->
|
|
|
|
acc >>= fun datas ->
|
|
|
|
match String.cut ~sep:" " s with
|
|
|
|
| None -> Rresult.R.error_msgf "unable to parse entry %s" s
|
|
|
|
| Some (a, b) ->
|
|
|
|
(try Ok (Z.of_string a) with Invalid_argument x -> Error (`Msg x)) >>= fun s ->
|
|
|
|
Ok ((s, b) :: datas))
|
|
|
|
(Ok []) lines
|
|
|
|
|
|
|
|
let find_in_db label db tst =
|
|
|
|
try Ok (List.find tst db)
|
|
|
|
with Not_found -> Rresult.R.error_msgf "couldn't find %s in database" label
|
|
|
|
|
|
|
|
let find_name db name =
|
|
|
|
find_in_db name db (fun (_, n) -> String.equal n name) >>= fun (serial, _) ->
|
|
|
|
Ok serial
|
|
|
|
|
|
|
|
|
2017-05-26 14:30:34 +00:00
|
|
|
let jump _ db cacert cakey crl cn serial =
|
|
|
|
Nocrypto_entropy_unix.initialize () ;
|
|
|
|
match
|
|
|
|
(match cn, serial with
|
|
|
|
| x, y when x = "" && String.length y > 0 ->
|
|
|
|
(try Ok (Z.of_string y) with Invalid_argument x -> Error (`Msg x))
|
|
|
|
| x, y when y = "" ->
|
|
|
|
Bos.OS.File.read_lines (Fpath.v db) >>= fun entries ->
|
2018-10-22 23:48:24 +00:00
|
|
|
parse_db entries >>= fun db ->
|
|
|
|
find_name db x
|
2017-05-26 14:30:34 +00:00
|
|
|
| _ -> Error (`Msg "please provide either common name or serial!")) >>= fun serial ->
|
|
|
|
Bos.OS.File.read (Fpath.v cakey) >>= fun pk ->
|
|
|
|
let cakey = X509.Encoding.Pem.Private_key.of_pem_cstruct1 (Cstruct.of_string pk) in
|
|
|
|
Bos.OS.File.read (Fpath.v cacert) >>= fun cacert ->
|
|
|
|
let cacert = X509.Encoding.Pem.Certificate.of_pem_cstruct1 (Cstruct.of_string cacert) in
|
|
|
|
|
2017-12-20 22:06:51 +00:00
|
|
|
let this_update = Ptime_clock.now () in
|
2017-05-26 14:30:34 +00:00
|
|
|
let revoked = { X509.CRL.serial ; date = this_update ; extensions = [] } in
|
|
|
|
let crl = Fpath.v crl in
|
|
|
|
let issuer = X509.subject cacert in
|
|
|
|
(Bos.OS.File.exists crl >>= function
|
|
|
|
| true ->
|
|
|
|
Bos.OS.File.read crl >>= fun crl ->
|
|
|
|
(match X509.Encoding.crl_of_cstruct (Cstruct.of_string crl) with
|
|
|
|
| None -> Error (`Msg "couldn't parse CRL")
|
|
|
|
| Some c -> Ok (X509.CRL.revoke_certificate revoked ~this_update c cakey))
|
|
|
|
| false ->
|
|
|
|
Ok (X509.CRL.revoke
|
|
|
|
~issuer
|
|
|
|
~this_update
|
|
|
|
~extensions:[ (false, `CRL_number 0) ]
|
|
|
|
[ revoked ] cakey)) >>= fun new_crl ->
|
|
|
|
let crl_cs = X509.Encoding.crl_to_cstruct new_crl in
|
|
|
|
Bos.OS.File.write crl (Cstruct.to_string crl_cs) >>= fun () ->
|
|
|
|
(* create temporary certificate for uploading CRL *)
|
|
|
|
let name = "revoke" in
|
|
|
|
priv_key None name >>= fun key ->
|
|
|
|
let csr = X509.CA.request [ `CN name ] key in
|
|
|
|
let extensions = [ (false, `Unsupported (Vmm_asn.Oid.version, Vmm_asn.version_to_cstruct asn_version)) ;
|
2018-09-19 19:16:44 +00:00
|
|
|
(false, `Unsupported (Vmm_asn.Oid.command, Vmm_asn.command_to_cstruct `Crl)) ;
|
2017-05-26 14:30:34 +00:00
|
|
|
(false, `Unsupported (Vmm_asn.Oid.crl, crl_cs)) ] @ l_exts
|
|
|
|
in
|
|
|
|
sign ~dbname:(Fpath.v db) extensions issuer cakey csr (Duration.of_hour 1)
|
|
|
|
with
|
|
|
|
| Ok () -> `Ok ()
|
|
|
|
| Error (`Msg e) -> `Error (false, e)
|
|
|
|
|
|
|
|
open Cmdliner
|
|
|
|
|
|
|
|
let key =
|
|
|
|
let doc = "Private key" in
|
|
|
|
Arg.(required & pos 2 (some file) None & info [] ~doc)
|
|
|
|
|
|
|
|
let crl =
|
|
|
|
let doc = "Revocation list" in
|
|
|
|
Arg.(required & pos 3 (some file) None & info [] ~doc)
|
|
|
|
|
|
|
|
let cn =
|
|
|
|
let doc = "Common Name" in
|
|
|
|
Arg.(value & opt string "" & info [ "cn" ] ~doc)
|
|
|
|
|
|
|
|
let serial =
|
|
|
|
let doc = "Serial" in
|
|
|
|
Arg.(value & opt string "" & info [ "serial" ] ~doc)
|
|
|
|
|
|
|
|
let cmd =
|
|
|
|
Term.(ret (const jump $ setup_log $ db $ cacert $ key $ crl $ cn $ serial)),
|
|
|
|
Term.info "vmm_revoke" ~version:"%%VERSION_NUM%%"
|
|
|
|
|
|
|
|
let () = match Term.eval cmd with `Ok () -> exit 0 | _ -> exit 1
|