This commit is contained in:
swrup 2025-11-11 02:07:51 +01:00
parent aa2ff7b2f0
commit 2f3113f55d
11742 changed files with 1223940 additions and 0 deletions

View file

@ -0,0 +1,3 @@
_build
_opam
.merlin

View file

@ -0,0 +1,2 @@
version = 0.27.0
profile=conventional

View file

@ -0,0 +1,125 @@
# v3.117 (2025-10-13)
* Update to NSS 3.117 (2025-10-03)
# v3.115 (2025-08-15)
* Update to NSS 3.115 (2025-08-15)
# v3.114 (2025-07-24)
* Update to NSS 3.114 (2025-07-17)
# v3.113.1 (2025-07-02)
* Update to NSS 3.113.1 (2025-07-01)
* Provide the function `trust_anchors`
# v3.108-1 (2025-02-05)
* Use mirage-ptime instead of functorising over PCLOCK (#11 @hannesm)
# v3.108 (2025-02-04)
* Update to NSS 3.108 (Feb 3rd 2025)
# v3.107 (2024-11-27)
* Update to NSS 3.107 (Nov 21st 2024)
# v3.104 (2024-09-02)
* Update to NSS 3.104 (Aug 30th 2024)
# v3.103 (2024-08-13)
* Update to NSS 3.103 (Aug 1st 2024)
# v3.101-1 (2024-07-24)
* Delete cstruct and replace it by string (@dinosaure, #9)
# v3.101 (2024-06-11)
* Update to NSS 3.101 (June 7th 2024)
# v3.98 (2024-02-26)
* Update to NSS 3.98 (Feb 15th 2024)
# v3.95 (2023-11-28)
* Update to NSS 3.95 (Nov 16th 2023)
# v3.92 (2023-08-03)
* Update to NSS 3.92 (July 27th 2023)
# v3.89.1 (2023-05-06)
* Update to NSS 3.89.1 (May 5th 2023)
# v3.86 (2022-12-12)
* Update to NSS 3.86 (Dec 8th 2022)
# v3.83 (2022-09-16)
* Update to NSS 3.83 (Sep 15th 2022)
# v3.80 (2022-07-04)
* Update to NSS 3.80 (Jun 23rd 2022)
# v3.77 (2022-04-22)
* Update to NSS 3.77 (Mar 31th 2022)
* Update to cmdliner 1.1.0 (#6)
# v3.74 (2022-01-07)
* Update to NSS 3.74 (Jan 6th 2022)
* Update to NSS 3.73.1, 3.73, 3.72 (no changes in certdata.txt)
# v3.71.0.1 (2021-10-07)
* Adapt to X509 0.15.0 API changes
# v3.71 (2021-10-06)
* Update to NSS 3.71 (Sep 30th 2021)
* Remove rresult and hex dependencies
# v3.66 (2021-06-01)
* Update to NSS 3.66 (May 27th 2021)
# v3.64.0.1 (2021-04-22)
* Update to X509 0.13.0 API (still using NSS 3.64)
# v3.64 (2021-04-18)
* Update to NSS 3.64 (Apr 15th 2021)
# v3.63.1 (2021-04-14)
* Update to NSS 3.63.1 (Apr 9th 2021)
# v3.63 (2021-03-18)
* Update to NSS 3.63 (Mar 18th 2021)
* Update to NSS 3.62 (Feb 19th 2021), no changes in certdata.txt
* Update to NSS 3.61 (Jan 22th 2021), no changes in certdata.txt
# v3.60 (2020-12-20)
* Update to NSS 3.60 release (Dec 11th 2020)
# v3.59 (2020-11-15)
* Update to NSS 3.59 release (Nov 13th 2020)
# v3.57 (2020-10-13)
* Initial public release (version numbers meet NSS releases)

View file

@ -0,0 +1,15 @@
## ISC License
Copyright (c) 2020, The MirageOS contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View file

@ -0,0 +1,7 @@
# ca-root-nss
Trust anchors extracted from Mozilla's NSS certdata.txt package, to be used
in MirageOS unikernels.
To update trust anchors, please adjust the commit hash to the latest NSS
release in `lib/dune`, remove `certdata.txt`, and run dune build.

View file

@ -0,0 +1,4 @@
(executable
(name extract_from_certdata)
(public_name extract-from-certdata)
(libraries logs logs.fmt logs.cli fmt fmt.tty fmt.cli bos cmdliner x509))

View file

@ -0,0 +1,290 @@
(* input is a certdata.txt from nss, output is a ml file with the trust anchors *)
(* ideas from FreeBSD's security/ca-root-nss perl script, available at:
https://github.com/freebsd/freebsd-ports/blob/master/security/ca_root_nss/files/MAca-bundle.pl.in *)
let until_end data =
let rec go acc = function
| [] -> invalid_arg "unexpected end of input (expected END)"
| "END" :: tl -> (List.rev acc, tl)
| x :: tl -> go (x :: acc) tl
in
go [] data
let decode_octal data =
let nums = String.split_on_char '\\' data in
let nums = List.filter (fun s -> String.length s = 3) nums in
let numbers = List.map (fun s -> int_of_string ("0o" ^ s)) nums in
let out = Bytes.create (List.length nums) in
List.iteri (fun i x -> Bytes.set out i (char_of_int x)) numbers;
Bytes.unsafe_to_string out
let label_token = "CKA_LABEL UTF8 "
let serial_token = "CKA_SERIAL_NUMBER MULTILINE_OCTAL"
let is_prefix token x =
let tl = String.length token in
String.length x >= tl && String.(equal (sub x 0 tl) token)
let is_suffix token x =
let tl = String.length token in
let xl = String.length x in
xl >= tl && String.(equal (sub x (xl - tl) tl) token)
let strip_prefix token x =
let tl = String.length token in
let xl = String.length x in
String.sub x tl (xl - tl)
let label_serial id serial = function
| [] -> assert false
| x :: tl ->
if is_prefix label_token x then
let id = strip_prefix label_token x in
(Some id, serial, tl)
else if String.equal x serial_token then
let serial, rest = until_end tl in
let serial = decode_octal (String.concat "" serial) in
(id, Some serial, rest)
else (id, serial, tl)
let get_id_serial id serial =
let id = match id with None -> invalid_arg "no ID" | Some id -> id
and serial =
match serial with None -> invalid_arg "no serial" | Some s -> s
in
(id, serial)
let grab_cert input =
let rec go id serial cert = function
| [] -> (
let id, serial = get_id_serial id serial in
match cert with
| None -> invalid_arg "missing certificate"
| Some x -> (id, serial, x))
| "CKA_VALUE MULTILINE_OCTAL" :: tl ->
let cert, tl = until_end tl in
go id serial (Some cert) tl
| tl ->
let id, serial, tl = label_serial id serial tl in
go id serial cert tl
in
go None None None input
let trust_ok_token = "CKT_NSS_TRUSTED_DELEGATOR"
and not_trusted_token = "CKT_NSS_NOT_TRUSTED"
and verify_token = "CKT_NSS_MUST_VERIFY_TRUST"
let web_server_token = "CKA_TRUST_SERVER_AUTH"
and email_token = "CKA_TRUST_EMAIL_PROTECTION"
and code_signing_token = "CKA_TRUST_CODE_SIGNING"
let ck_trust_token = " CK_TRUST "
let extract_trust x =
let is_trusted x =
if is_suffix trust_ok_token x then `Trusted
else if is_suffix not_trusted_token x then `Not_trusted
else if is_suffix verify_token x then `Must_verify
else invalid_arg "unknown trust setting"
in
if is_prefix (web_server_token ^ ck_trust_token) x then
Some (`Web, is_trusted x)
else if is_prefix (email_token ^ ck_trust_token) x then
Some (`Email, is_trusted x)
else if is_prefix (code_signing_token ^ ck_trust_token) x then
Some (`Code_signing, is_trusted x)
else None
let grab_trust input =
let rec go id serial trust = function
| [] ->
let id, serial = get_id_serial id serial in
(id, serial, trust)
| x :: tl -> (
match extract_trust x with
| None ->
let id, serial, tl = label_serial id serial (x :: tl) in
go id serial trust tl
| Some y -> go id serial (y :: trust) tl)
in
go None None [] input
let add (certs, trust) mode acc =
match mode with
| Some `Cert -> (List.rev acc :: certs, trust)
| Some `Trust -> (certs, List.rev acc :: trust)
| None -> (certs, trust)
let rec split_into_certs_and_trust dbs mode acc = function
| [] ->
let certs, trust = add dbs mode acc in
(List.rev certs, List.rev trust)
| "CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE" :: tl ->
let dbs = add dbs mode acc in
split_into_certs_and_trust dbs (Some `Cert) [] tl
| "CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST" :: tl ->
let dbs = add dbs mode acc in
split_into_certs_and_trust dbs (Some `Trust) [] tl
| x :: tl -> split_into_certs_and_trust dbs mode (x :: acc) tl
module M = Map.Make (struct
type t = string * string
let compare (lbl, serial) (lbl', serial') =
match String.compare lbl lbl' with
| 0 -> String.compare serial serial'
| y -> y
end)
let to_hex s =
let char_hex n =
Char.unsafe_chr (n + if n < 10 then Char.code '0' else Char.code 'a' - 10)
in
let slen = String.length s in
let out = Bytes.create (slen * 2) in
for i = 0 to pred slen do
let c = Char.code s.[i] in
Bytes.unsafe_set out (i * 2) (char_hex (c lsr 4));
Bytes.unsafe_set out ((i * 2) + 1) (char_hex (c land 0x0f))
done;
Bytes.unsafe_to_string out
let decode data =
let certs, trust = split_into_certs_and_trust ([], []) None [] data in
let db =
List.fold_left
(fun db data ->
let id, serial, cert = grab_cert data in
let db =
M.update (id, serial)
(function
| None -> Some (Some cert, None)
| Some (None, x) -> Some (Some cert, x)
| Some (Some _, _) ->
Logs.warn (fun m ->
m "cert with %s (serial %s) already present" id
(to_hex serial));
invalid_arg "duplicate certificate")
db
in
db)
M.empty certs
in
List.fold_left
(fun db data ->
let id, serial, trust = grab_trust data in
let db =
M.update (id, serial)
(function
| None -> Some (None, Some trust)
| Some (x, None) -> Some (x, Some trust)
| Some (_, Some _) ->
Logs.warn (fun m ->
m "trust with %s (serial %s) already present" id
(to_hex serial));
invalid_arg "duplicate trust")
db
in
db)
db trust
let filter_trusted ?(purpose = fun (_, _) -> true) db =
let is_trusted ys =
let y = List.filter purpose ys in
List.exists (function _, `Trusted -> true | _ -> false) y
&& List.for_all (function _, `Not_trusted -> false | _ -> true) ys
in
M.fold
(fun (id, serial) (cert, trust) (acc, untrusted) ->
match (cert, trust) with
| None, _ ->
Logs.debug (fun m ->
m "ignoring %s (serial %s), no corresponding certificate" id
(to_hex serial));
(acc, untrusted)
| Some _, None ->
Logs.warn (fun m ->
m "ignoring %s (serial %s), no corresponding trust" id
(to_hex serial));
(acc, succ untrusted)
| Some cert, Some t ->
if is_trusted t then (M.add (id, serial) cert acc, untrusted)
else (
Logs.warn (fun m ->
m "Untrusted certificate %s (serial %s)" id (to_hex serial));
(acc, succ untrusted)))
db (M.empty, 0)
let header =
"(* automatically extracted from certdata.txt by ca-certs-nss v3.117. *)"
let stats ucount tcount dcount =
Fmt.str "(* processed %d certificates, %d untrusted, %d trusted. *)%s"
(ucount + tcount + dcount)
ucount tcount
(if dcount > 0 then
"\n(* Omitted " ^ string_of_int dcount ^ " certificates (decoding). *)"
else "")
let to_ml untrusted db =
let certs, decoding_issues =
M.fold
(fun (lbl, _) cert (acc, dec) ->
let der = decode_octal (String.concat "" cert) in
match X509.Certificate.decode_der der with
| Ok _cert ->
(("(* " ^ lbl ^ " *) \"" ^ String.escaped der ^ "\"") :: acc, dec)
| Error (`Msg msg) ->
Logs.warn (fun m -> m "failed to decode certificate: %s" msg);
(acc, succ dec))
db ([], 0)
in
String.concat "\n"
[
header;
stats untrusted (List.length certs) decoding_issues;
"";
"let certificates = [";
" " ^ String.concat ";\n " (List.rev certs);
"]";
"";
]
let jump () filename output =
Result.bind
(Bos.OS.File.read_lines (Fpath.v filename))
(fun data ->
let certs = decode data in
let trusted_certs, untrusted = filter_trusted certs in
Logs.debug (fun m ->
m "found %d certificates (%d total):" (M.cardinal trusted_certs)
(M.cardinal certs));
let out = to_ml untrusted trusted_certs in
let fn = match output with None -> "-" | Some filename -> filename in
Bos.OS.File.write (Fpath.v fn) out)
let setup_log style_renderer level =
Fmt_tty.setup_std_outputs ?style_renderer ();
Logs.set_level level;
Logs.set_reporter (Logs_fmt.reporter ~dst:Format.std_formatter ())
open Cmdliner
let setup_log =
Term.(const setup_log $ Fmt_cli.style_renderer () $ Logs_cli.level ())
let input =
let doc = "Full path to certdata.txt." in
Arg.(required & pos 0 (some file) None & info [] ~doc ~docv:"CERTDATA.TXT")
let output =
let doc = "Output filename (defaults to stdout)." in
Arg.(value & opt (some string) None & info [ "output" ] ~doc)
let cmd =
let doc = "Extract NSS certdata.txt into OCaml code" in
let term = Term.(term_result (const jump $ setup_log $ input $ output))
and info = Cmd.info "extract-from-certdata" ~version:"3.117" ~doc in
Cmd.v info term
let () = exit (Cmd.eval cmd)

View file

@ -0,0 +1,46 @@
version: "3.117"
# This file is generated by dune, edit dune-project instead
opam-version: "2.0"
synopsis: "X.509 trust anchors extracted from Mozilla's NSS"
description: """
Trust anchors extracted from Mozilla's NSS certdata.txt package,
to be used in MirageOS unikernels.
"""
maintainer: ["Hannes Mehnert <hannes@mehnert.org>"]
authors: ["Hannes Mehnert <hannes@mehnert.org>"]
license: "ISC"
homepage: "https://github.com/mirage/ca-certs-nss"
doc: "https://mirage.github.io/ca-certs-nss/doc"
bug-reports: "https://github.com/mirage/ca-certs-nss/issues"
depends: [
"dune" {>= "2.7"}
"mirage-ptime" {>= "4.0.0"}
"x509" {>= "1.0.0"}
"ocaml" {>= "4.13.0"}
"digestif" {>= "1.2.0"}
"logs" {build}
"fmt" {build & >= "0.8.7"}
"bos" {build}
"cmdliner" {build & >= "1.1.0"}
"alcotest" {with-test}
"odoc" {with-doc}
]
conflicts: [
"result" {< "1.5"}
]
build: [
["dune" "subst"] {dev}
[
"dune"
"build"
"-p"
name
"-j"
jobs
"@install"
"@runtest" {with-test}
"@doc" {with-doc}
]
]
dev-repo: "git+https://github.com/mirage/ca-certs-nss.git"
tags: ["org:mirage"]

View file

@ -0,0 +1 @@
tags: ["org:mirage"]

View file

@ -0,0 +1,32 @@
(lang dune 2.7)
(name ca-certs-nss)
(version v3.117)
(generate_opam_files true)
(source (github mirage/ca-certs-nss))
(documentation "https://mirage.github.io/ca-certs-nss/doc")
(license ISC)
(maintainers "Hannes Mehnert <hannes@mehnert.org>")
(authors "Hannes Mehnert <hannes@mehnert.org>")
(package
(name ca-certs-nss)
(depends
(mirage-ptime (>= 4.0.0))
(x509 (>= 1.0.0))
(ocaml (>= 4.13.0))
(digestif (>= 1.2.0))
(logs :build)
(fmt (and :build (>= 0.8.7)))
(bos :build)
(cmdliner (and :build (>= 1.1.0)))
(alcotest :with-test))
(conflicts (result (< 1.5)))
(synopsis "X.509 trust anchors extracted from Mozilla's NSS")
(description
"\> Trust anchors extracted from Mozilla's NSS certdata.txt package,
"\> to be used in MirageOS unikernels.
)
; tags are not included before (lang dune 2.0)
; so an opam template is necessary until then
(tags (org:mirage)))

View file

@ -0,0 +1,15 @@
let trust_anchors =
List.fold_left
(fun acc data ->
Result.bind acc (fun acc ->
Result.map
(fun cert -> cert :: acc)
(X509.Certificate.decode_der data)))
(Ok []) Trust_anchor.certificates
let authenticator =
let time () = Some (Mirage_ptime.now ()) in
fun ?crls ?allowed_hashes () ->
Result.map
(X509.Authenticator.chain_of_trust ~time ?crls ?allowed_hashes)
trust_anchors

View file

@ -0,0 +1,11 @@
val trust_anchors : (X509.Certificate.t list, [> `Msg of string ]) result
(** [trust_anchors] are the trust anchors extracted from NSS certdata.txt. *)
val authenticator :
?crls:X509.CRL.t list ->
?allowed_hashes:Digestif.hash' list ->
unit ->
(X509.Authenticator.t, [> `Msg of string ]) result
(** [authenticator ~crls ~hash_whitelist ()] is an authenticator with the
provided revocation lists, and allowed_hashes. The trust anchors are based
on the extraction from NSS' certdata.txt. *)

View file

@ -0,0 +1,22 @@
; to update, browse to https://hg.mozilla.org/projects/nss/tags
; find the last release (click on the tag, find the "changeset .. ID" line)
; rm -f lib/certdata.txt
; dune build lib/certdata.txt
; mv _build/default/lib/certdata.txt lib
;(rule
; (targets certdata.txt)
; (action
; (bash
; "wget https://hg.mozilla.org/projects/nss/raw-file/6f5cf4984f6b0873cb689dd0c1f50a9264741b93/lib/ckfw/builtins/certdata.txt -O %{targets}")))
(rule
(targets trust_anchor.ml)
(deps certdata.txt)
(action
(run %{bin:extract-from-certdata} certdata.txt --output trust_anchor.ml)))
(library
(name ca_certs_nss)
(public_name ca-certs-nss)
(modules ca_certs_nss trust_anchor)
(libraries x509 mirage-ptime digestif))

View file

@ -0,0 +1,3 @@
(test
(name tests)
(libraries ca-certs-nss alcotest mirage-ptime.mock mirage-ptime.set))

File diff suppressed because it is too large Load diff