Module Name:    src
Committed By:   riastradh
Date:           Sat Aug 26 05:47:53 UTC 2023

Added Files:
        src/external/mpl/mozilla-certdata: Makefile
        src/external/mpl/mozilla-certdata/share: Makefile certdata.awk

Log Message:
mozilla-certdata: Makefile infrastructure.


To generate a diff of this commit:
cvs rdiff -u -r0 -r1.1 src/external/mpl/mozilla-certdata/Makefile
cvs rdiff -u -r0 -r1.1 src/external/mpl/mozilla-certdata/share/Makefile \
    src/external/mpl/mozilla-certdata/share/certdata.awk

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Added files:

Index: src/external/mpl/mozilla-certdata/Makefile
diff -u /dev/null src/external/mpl/mozilla-certdata/Makefile:1.1
--- /dev/null	Sat Aug 26 05:47:53 2023
+++ src/external/mpl/mozilla-certdata/Makefile	Sat Aug 26 05:47:53 2023
@@ -0,0 +1,9 @@
+#	$NetBSD: Makefile,v 1.1 2023/08/26 05:47:53 riastradh Exp $
+#
+
+.include <bsd.own.mk>
+
+.if ${MKSHARE} != "no"
+SUBDIR=	share
+.include <bsd.subdir.mk>
+.endif

Index: src/external/mpl/mozilla-certdata/share/Makefile
diff -u /dev/null src/external/mpl/mozilla-certdata/share/Makefile:1.1
--- /dev/null	Sat Aug 26 05:47:53 2023
+++ src/external/mpl/mozilla-certdata/share/Makefile	Sat Aug 26 05:47:53 2023
@@ -0,0 +1,80 @@
+#	$NetBSD: Makefile,v 1.1 2023/08/26 05:47:53 riastradh Exp $
+#
+
+MOZCERTS=	/usr/share/certs/mozilla
+FILESDIR=	${MOZCERTS}/all
+
+TRUSTDOMAINS=	server email code
+
+# Normally it is a bad idea to use file system globs to list sources in
+# a makefile, but we replace the directory wholesale on regen using the
+# same pattern below.  So in this case, maintaining an explicit list of
+# files would be more error-prone.
+CERTS!=		cd ${.CURDIR:Q} && echo certs/*.pem
+FILES+=		${CERTS}
+
+.for D in ${TRUSTDOMAINS}
+$D_CERTS!=	cat ${.CURDIR:Q}/$D.trust
+.  for C in ${$D_CERTS}
+SYMLINKS+=	${MOZCERTS}/all/$C.pem ${MOZCERTS}/$D/$C.pem
+.  endfor
+.endfor
+
+# The upstream Mozilla certdata.txt lives in the Mozilla nss repository
+# at https://hg.mozilla.org/projects/nss, under
+# lib/ckfw/builtins/certdata.txt.
+#
+# Updates:
+#
+#	1. Go to:
+#	   https://hg.mozilla.org/projects/nss/log/tip/lib/ckfw/builtins/certdata.txt
+#
+#	2. Find the top revision and follow the link to `diff'.
+#
+#	3. For the file lib/ckfw/builtins/certdata.txt, follow the link to
+#	   `file'.
+#
+#	4. Follow the link to `raw'.
+#
+#	5. Record the date of the latest revision and the URL to the
+#	   raw file in the comment below (includes hg revision).
+#
+#	6. Verify that the file matches when downloaded from at least
+#	   three different networks.  (Suggestions: Your home
+#	   residential network, a TNF server, and Tor.)
+#
+#	7. Once you have verified this, commit certdata.txt.
+#
+#	8. Review https://wiki.mozilla.org/CA/Additional_Trust_Changes
+#	   for new special cases and apply to certdata.awk if
+#	   appropriate.
+#
+#	9. After committing certdata.txt and updating certdata.awk, run
+#	   `make regen' and verify that it builds and installs and
+#	   generally looks sensible.
+#
+#	10. Once you have verified that it builds and installs, cvs add
+#	   any new files and cvs rm any deleted files under certs/,
+#	   and commit certs/ and *.trust.
+#
+# Latest revision, from 2023-07-19:
+#
+# https://hg.mozilla.org/projects/nss/raw-file/f479bdba756c78ef9355a48c88744c69fdb4768e/lib/ckfw/builtins/certdata.txt
+#
+regen: .PHONY
+	rm -f certs/*.pem
+	rm -f ${TRUSTDOMAINS:=.trust}
+	mkdir tmp
+	awk -f certdata.awk \
+		-v CERTDIR=certs \
+		-v CODETRUST=code.trust \
+		-v EMAILTRUST=email.trust \
+		-v OPENSSL=openssl \
+		-v SERVERTRUST=server.trust \
+		-v WORKDIR=tmp \
+		<${.CURDIR:Q}/../dist/certdata.txt
+	rm -rf tmp
+
+.include <bsd.files.mk>
+.include <bsd.inc.mk>		# XXX
+.include <bsd.links.mk>
Index: src/external/mpl/mozilla-certdata/share/certdata.awk
diff -u /dev/null src/external/mpl/mozilla-certdata/share/certdata.awk:1.1
--- /dev/null	Sat Aug 26 05:47:53 2023
+++ src/external/mpl/mozilla-certdata/share/certdata.awk	Sat Aug 26 05:47:53 2023
@@ -0,0 +1,582 @@
+#!/usr/bin/awk -f
+#
+# Copyright (c) 2023 The NetBSD Foundation, Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+function quotify(x) {
+	gsub(/'/, "'\\''", x)
+	return "'"x"'"
+}
+
+function err(s) {
+	printf "%s: line %s: error: %s\n", ARGV[0], NR, s >"/dev/stderr"
+	printf "# %s\n", $0 >"/dev/stderr"
+	errors++
+}
+
+function symlink(target, link,  cmd, status) {
+	cmd = sprintf("ln -sfn %s %s", quotify(target), quotify(link))
+	status = system(cmd)
+	if (status != 0)
+		err(sprintf("ln failed with status %d", status))
+}
+
+function reset() {
+	cka_class = ""
+	label = ""
+	lolab = ""
+	certpem = ""
+	certworkdir = ""
+	skipping = 0
+}
+
+function skip() {
+	if (VERBOSE)
+		printf "line %d: skip from: %s\n", NR, $0
+	skipping = 1
+}
+
+function parseoctal(s, i, n,  x) {
+	x = 0
+	n += i
+	for (; i < n; i++) {
+		x *= 8
+		x += int(substr(s, i, 1))
+	}
+	return x
+}
+
+function writeoctaldata(f, desc,  warned, status) {
+	if ($2 != "MULTILINE_OCTAL") {
+		err(sprintf("%s: Invalid %s type: %s", label, desc, $2))
+		skip()
+		return -1
+	}
+	warned = 0
+	while (getline) {
+		if ($0 == "END")
+			break
+		for (i = 0; i < length($0); i += 4) {
+			if (substr($0, i + 1, 4) !~ /\\[0-7][0-7][0-7]/) {
+				if (!warned)
+					err(sprintf("%s: Invalid %s data",
+					    label, desc))
+				warned = 1
+				break
+			}
+			printf "%c", parseoctal($0, i + 2, 3) >f
+		}
+	}
+	status = close(f)
+	if ($0 != "END") {
+		err(sprintf("%s: Invalid octal data", label))
+		warned = 1
+	}
+	if (warned)
+		return -1
+	return status
+}
+
+function checkoctaldata(f, desc,  fcheck) {
+	fcheck = f".tmp"
+	if (writeoctaldata(fcheck, desc) != 0)
+		return
+	cmd = sprintf("cmp -- %s %s >/dev/null && rm -- %s",
+	    quotify(f), quotify(fcheck), quotify(fcheck))
+	if (system(cmd) != 0) {
+		err(sprintf("%s: %s mismatch", label, desc))
+		skip()
+	}
+}
+
+function writecheckoctaldata(f, desc, dowrite) {
+	if (dowrite)
+		writeoctaldata(f, desc)
+	else
+		checkoctaldata(f, desc)
+}
+
+function skipoctaldata(desc,  warned) {
+	if ($2 != "MULTILINE_OCTAL") {
+		err(sprintf("%s: Invalid %s type: %s", label, desc, $2))
+		skip()
+		return -1
+	}
+	warned = 0
+	while (getline) {
+		if ($0 == "END")
+			return 0
+		if ($0 !~ /(\\[0-7][0-7][0-7])*/ && !warned) {
+			err(sprintf("%s: Invalid %s data", label, desc))
+			warned = 1
+		}
+	}
+	err(sprintf("%s: Invalid octal data", label))
+	skip()
+	return 1
+}
+
+function distrust_after(desc) {
+	if ($2 == "CK_BBOOL" && $3 == "CK_FALSE")
+		return
+	if ($2 == "MULTILINE_OCTAL") {
+		skipoctaldata(sprintf("%s distrust deadline", $2))
+	} else {
+		err(sprintf("%s: Unknown %s distrust type %d, value: %s",
+		    label, desc, $2, $3))
+	}
+	if (VERBOSE)
+		printf "line %d: distrust for %s: %s\n", NR, desc, label
+	distrusted[lolab] = 1
+}
+
+function addtrust(trustfile, desc) {
+	if (desc":"lolab in trust_lineno) {
+		err(sprintf("%s: Multiple trust lines for %s, first at %d",
+		    label, desc, trust_lineno[desc":"lolab]))
+		skip()
+		return
+	}
+	trust_lineno[desc":"lolab] = NR
+	if ($3 == "CKT_NSS_TRUSTED" || $3 == "CKT_NSS_TRUSTED_DELEGATOR") {
+		if (distrusted[lolab]) {
+			if (VERBOSE) {
+				printf "line %d: distrusted for %s\n", \
+				    NR, desc
+			}
+		} else {
+			if (VERBOSE) {
+				printf "line %d: trusted for %s\n", \
+				    NR, desc
+			}
+			printf "%s\n", label >trustfile
+		}
+	} else if ($3 == "CKT_NSS_MUST_VERIFY_TRUST" ||
+	    $3 == "CKT_NSS_UNTRUSTED" ||
+	    $3 == "CKT_NSS_NOT_TRUSTED") {
+		if (VERBOSE) {
+			printf "line %d: untrusted for %s\n", \
+			    NR, desc
+		}
+	} else {
+		err(sprintf("%s: Unknown trust designation for %s: %s",
+		    label, desc, $3))
+	}
+}
+
+
+BEGIN {
+	if (ARGV[0] == "awk")
+		ARGV[0] = "certdata"
+	if (!CERTDIR) {
+		printf "%s: specify -v CERTDIR=...", ARGV[0] >"/dev/stderr"
+		exit 1
+	}
+	if (!WORKDIR) {
+		printf "%s: specify -v WORKDIR=...", ARGV[0] >"/dev/stderr"
+		exit 1
+	}
+	if (!OPENSSL) {
+		printf "%s: specify -v OPENSSL=...", ARGV[0] >"/dev/stderr"
+		exit 1
+	}
+	if (!SERVERTRUST)
+		SERVERTRUST = "/dev/null"
+	if (!EMAILTRUST)
+		EMAILTRUST = "/dev/null"
+	if (!CODETRUST)
+		CODETRUST = "/dev/null"
+	printf "" >SERVERTRUST
+	printf "" >EMAILTRUST
+	printf "" >CODETRUST
+	errors = 0
+	reset()
+
+	# Special cases.  See
+	# https://wiki.mozilla.org/CA/Additional_Trust_Changes for
+	# details.
+
+	# `The Turkish Government CA is name-constrained to *.tr.'
+	#
+	# Implemented in Firefox by
+	# https://phabricator.services.mozilla.com/D177242, but OpenSSL
+	# has no mechanism to implement this constraint, so we just
+	# exclude it altogether.
+	special_distrust["TUBITAK_Kamu_SM_SSL_Kok_Sertifikasi_-_Surum_1"] = 1
+}
+
+END {
+	# Make sure the special cases have been applied.
+	for (label in special_distrust)
+		err("special distrust not found: %s.pem", label)
+
+	fflush()		# flush all
+	close(SERVERTRUST)
+	close(EMAILTRUST)
+	close(CODETRUST)
+	if (errors) {
+		printf "%s: exiting with failure on %d error%s\n", ARGV[0], \
+		    errors, (errors == 1 ? "" : "s") \
+		    >"/dev/stderr"
+		exit 1
+	}
+}
+
+/^ *#/ {			# comment
+	next
+}
+
+/^ *$/ {
+	next
+}
+
+$1 == "BEGINDATA" {
+	next
+}
+
+$1 == "CKA_CLASS" {
+	reset()
+}
+
+skipping {
+	if (VERBOSE)
+		printf "line %d: skipping: %s\n", NR, $0
+	next
+}
+
+$1 == "CKA_CLASS" && $2 != "CK_OBJECT_CLASS" {
+	err(sprintf("Invalid class: %s", $2))
+	skip()
+	next
+}
+
+$1 == "CKA_CLASS" && $3 == "CKO_NSS_BUILTIN_ROOT_LIST" {
+	skip()
+	next
+}
+
+$1 == "CKA_CLASS" {
+	cka_class = $3
+	next
+}
+
+$1 == "CKA_TOKEN" ||
+$1 == "CKA_NSS_MOZILLA_CA_POLICY" ||
+0 {
+	if ($2 != "CK_BBOOL") {
+		err(sprintf("Invalid %s type: %s; value: %s", $1, $2, $3))
+		next
+	}
+	if ($3 != "CK_TRUE")
+		err(sprintf("%s is false", $1))
+	next
+}
+
+$1 == "CKA_MODIFIABLE" ||
+$1 == "CKA_PRIVATE" ||
+$1 == "CKA_TRUST_STEP_UP_APPROVED" ||
+0 {
+	if ($2 != "CK_BBOOL") {
+		err(sprintf("Invalid %s type: %s; value: %s", $1, $2, $3))
+		next
+	}
+	if ($3 != "CK_FALSE")
+		err(sprintf("%s is true", $1))
+	next
+}
+
+$1 == "CKA_LABEL" {
+	if ($2 != "UTF8") {
+		err(sprintf("Non-UTF8 label type: %s; value: %s", $2, $3))
+		skip()
+		next
+	}
+
+	# Clear the `CKA_LABEL UTF8' fields.  (`shift 2', in sh, except
+	# that doesn't work here in awk.)
+	sub(/CKA_LABEL +UTF8 +/, "", $0)
+
+	# Forbid embedded ", \, and /, as well as bunch of others.
+	#
+	# - We forbid embedded " because it's not clear what the escape
+	#   sequence is.
+	#
+	# - We forbid \ in case there are escape sequences we don't
+	#   know.
+	#
+	# - We forbid / so that we can always form a directory
+	#   component
+	#
+	# We immediately forbid a bunch of others that might be
+	# metacharacters or otherwise problematic, so that the next
+	# person to update certdata will be forced to consciously think
+	# about how to handle them.
+	if ($0 !~ /^"[^[:cntrl:]!"#$%&\*\/:;?\[\\\]\^`\|~]*"$/) {
+		err(sprintf("Invalid characters in label: %s", $3))
+		skip()
+		next
+	}
+
+	# Nix the "quotes".
+	label = substr($0, 2, length($0) - 2)
+
+	# XXX The `renaming to' messages are inconsistent about whether
+	# they apply pre-substitution or post-substitution, so some
+	# have spaces and some have underscores.  Oh well.
+
+	# Special cases: Avoid parentheses in two CA names, and
+	# non-US-ASCII in one CA name.  It is regrettable to limit
+	# ourselves to an anglocentric worldview like this, but this
+	# will avoid potential problems with file system pathname
+	# encoding and canonicalization downstream.
+	if (label ~ /^NetLock Arany \(Class Gold\) F.*$/) {
+		label = "NetLock Arany Class Gold"
+		if (cka_class == "CKO_CERTIFICATE") {
+			printf "line %s: special characters," \
+			    " renaming to \"%s\"\n",	      \
+			    NR, label
+		}
+	}
+	if (label == "LAWtrust Root CA2 (4096)") {
+		label = "LAWtrust Root CA2 4096"
+		if (cka_class == "CKO_CERTIFICATE") {
+			printf "line %s: special characters," \
+			    " renaming to \"%s\"\n",	      \
+			    NR, label
+		}
+	}
+
+	# Avoid spaces in filenames, because Unix.  Not that filenames
+	# can't have spaces in Unix, but a lot of downstream tools may
+	# get confused by them.
+	gsub(/ /, "_", label)
+
+	# Make sure it uses onlypathname-safe characters.
+	if (label ~ /[^[:alnum:]._-]/ || label ~ /^\./) {
+		err(sprintf("Special CA label: %s", label))
+		skip()
+		next
+	}
+
+	# Make sure it's not empty.
+	if (length(label) == 0) {
+		err("Empty label")
+		skip()
+		next
+	}
+
+	# Make sure it fits within a reasonable limit as a filename.
+	if (length(label) > 100) {
+		err(sprintf("Label too long, %d bytes > max %d: %s",
+		    length(label), 100, label))
+		skip()
+		next
+	}
+
+	# If this defines the certificate, check for duplicates; if a
+	# duplicate is found, assign a counter suffix.
+	#
+	# XXX This collision numbering might not be stable across
+	# updates.  What to do?  Use the serial number?
+	#
+	# XXX This doesn't use Unicode case-folding.  Let's hope we
+	# don't have anything that is a collision under casefold but
+	# not under US-ASCII-limited tolower.
+	lolab = tolower(label)
+	if (cka_class == "CKO_CERTIFICATE") {
+		if (VERBOSE)
+			printf "line %d: CA \"%s\"\n", NR, label
+		if (lolab in label_lineno) {
+			label = sprintf("%s.%d", label, ++label_counter[lolab])
+			lolab = tolower(label)
+			printf "line %s: duplicate, renaming to \"%s\"\n", \
+			    NR, label
+		}
+		label_lineno[lolab] = NR
+	} else {
+		if (VERBOSE)
+			printf "line %d: trust \"%s\"\n", NR, label
+		# Hack: Take the highest-numbered counter for this label.
+		if (lolab in label_counter) {
+			label = sprintf("%s.%d", label, label_counter[lolab])
+			lolab = tolower(label)
+			printf "line %s: assuming duplicate is \"%s\"\n", \
+			    NR, label
+		}
+		if (!(lolab in label_lineno)) {
+			err(snprintf("Missing label: %s", label))
+			skip()
+			next
+		}
+	}
+
+	# Apply special cases.
+	if (cka_class == "CKO_CERTIFICATE") {
+		if (label in special_distrust) {
+			printf "line %s: specially distrusting \"%s\"\n", \
+			    NR, label
+			distrusted[lolab] = 1
+			delete special_distrust[label]
+		}
+	}
+
+	# Compute where this certificate will lives and a workspace.
+	certpem = CERTDIR"/"label".pem"
+	certworkdir = WORKDIR"/"label
+
+	# If this defines the certificate, create the directory.
+	# Otherwise, make sure the directory is there already.
+	if (cka_class == "CKO_CERTIFICATE") {
+		if (system(sprintf("mkdir -- %s", quotify(certworkdir))) \
+		    != 0) {
+			errors++
+			skip()
+			next
+		}
+	} else {
+		if (system(sprintf("test -f %s", quotify(certpem))) != 0) {
+			err("%s: Missing certificate for %s", label,
+			    cka_class)
+		}
+		if (system(sprintf("test -d %s", quotify(certworkdir))) != 0)
+			err("%s: Missing directory for %s", label, cka_class)
+	}
+
+	next
+}
+
+# Remaining rules assume we are in the middle of an object block and we
+# have a label.
+
+!label {
+	err(sprintf("%s: missing label", $1))
+	skip()
+	next
+}
+
+$1 == "CKA_CERTIFICATE_TYPE" {
+	if ($2 != "CK_CERTIFICATE_TYPE") {
+		err(sprintf("%s: Invalid certificate type type: %s",
+		    label, $2))
+		skip()
+		next
+	}
+	if ($3 != "CKC_X_509") {
+		err(sprintf("%s: Unknown certificate type: %s", label, $2))
+		skip()
+		next
+	}
+	next
+}
+
+$1 == "CKA_SUBJECT" {
+	writeoctaldata(certworkdir"/subject", "subject")
+	next
+}
+
+$1 == "CKA_ID" {
+	if ($0 != "CKA_ID UTF8 \"0\"") {
+		err(sprintf("%s: Invalid id: %s", label, $0))
+		skip()
+		next
+	}
+	next
+}
+
+$1 == "CKA_ISSUER" {
+	writecheckoctaldata(certworkdir"/issuer", "issuer",
+	    cka_class == "CKO_CERTIFICATE")
+	next
+}
+
+$1 == "CKA_SERIAL_NUMBER" {
+	writecheckoctaldata(certworkdir"/serial", "serial number",
+	    cka_class == "CKO_CERTIFICATE")
+	next
+}
+
+$1 == "CKA_VALUE" {
+	if (writeoctaldata(certworkdir"/cert.der", "certificate data"))
+		next
+	if (system(sprintf("%s x509 -inform DER -outform PEM <%s >%s",
+	    quotify(OPENSSL),
+	    quotify(certworkdir"/cert.der"),
+	    quotify(certpem))))
+		err(sprintf("%s: openssl x509 failed", label))
+	next
+}
+
+$1 == "CKA_CERT_SHA1_HASH" {
+	writeoctaldata(certworkdir"/hash.sha1", "SHA-1 hash")
+	next
+}
+
+$1 == "CKA_CERT_MD5_HASH" {
+	writeoctaldata(certworkdir"/hash.md5", "MD5 hash")
+	next
+}
+
+$1 == "CKA_NSS_SERVER_DISTRUST_AFTER" {
+	distrust_after("server")
+	next
+}
+
+$1 == "CKA_NSS_EMAIL_DISTRUST_AFTER" {
+	distrust_after("email")
+	next
+}
+
+$1 !~ /^CKA_TRUST_/ {
+	err(sprintf("%s: Unknown line: %s", label, $0))
+	skip()
+	next
+}
+
+$2 != "CK_TRUST" {
+	err(sprintf("%s: Invalid trust line: %s", label, $0))
+	skip()
+	next
+}
+
+# Remaining rules assume we are on a valid CKA_TRUST_* attribute.
+
+$1 == "CKA_TRUST_SERVER_AUTH" {
+	addtrust(SERVERTRUST, "server authentication")
+	next
+}
+
+$1 == "CKA_TRUST_EMAIL_PROTECTION" {
+	addtrust(EMAILTRUST, "email protection")
+	next
+}
+
+$1 == "CKA_TRUST_CODE_SIGNING" {
+	addtrust(CODETRUST, "code signing")
+	next
+}
+
+{
+	err(sprintf("%s: Unknown trust domain: %s", label, $1))
+}

Reply via email to