diff options
| author | Dag-Erling Smørgrav <des@FreeBSD.org> | 2026-05-05 22:30:52 +0000 |
|---|---|---|
| committer | Dag-Erling Smørgrav <des@FreeBSD.org> | 2026-05-05 22:30:52 +0000 |
| commit | 2fef18ff594328a771b6aa659e8ffa5a7e076540 (patch) | |
| tree | d4c1f6ee9979b0b1ae59744517539fd316e8116b | |
| parent | c24b1d9359b899c7532d5b296f37cf3d74a36942 (diff) | |
| -rw-r--r-- | usr.sbin/certctl/certctl.8 | 15 | ||||
| -rw-r--r-- | usr.sbin/certctl/certctl.c | 81 | ||||
| -rw-r--r-- | usr.sbin/certctl/tests/certctl_test.sh | 3 |
3 files changed, 67 insertions, 32 deletions
diff --git a/usr.sbin/certctl/certctl.8 b/usr.sbin/certctl/certctl.8 index 2d38ce020c04..7df89e4d35d0 100644 --- a/usr.sbin/certctl/certctl.8 +++ b/usr.sbin/certctl/certctl.8 @@ -24,7 +24,7 @@ .\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd December 3, 2025 +.Dd April 24, 2026 .Dt CERTCTL 8 .Os .Sh NAME @@ -113,8 +113,19 @@ In addition, a bundle containing the trusted certificates is placed in .Ev BUNDLE . .It Ic untrust Add the specified file to the untrusted list. +Note that the next +.Ic rehash +will remove it unless a copy of it is also placed somewhere in a +directory included in +.Ev UNTRUSTPATH . .It Ic trust -Remove the specified file from the untrusted list. +Add the specified file to the trusted list, unless it is already +untrusted. +Note that the next +.Ic rehash +will remove it unless a copy of it is also placed somewhere in a +directory included in +.Ev TRUSTPATH . .El .Sh ENVIRONMENT .Bl -tag -width UNTRUSTDESTDIR diff --git a/usr.sbin/certctl/certctl.c b/usr.sbin/certctl/certctl.c index a53ed7b2b4b2..0a07703bf37b 100644 --- a/usr.sbin/certctl/certctl.c +++ b/usr.sbin/certctl/certctl.c @@ -636,23 +636,18 @@ write_bundle(const char *dir, const char *file, struct cert_tree *tree) * Returns the number of certificates loaded. */ static unsigned int -load_trusted(bool all, struct cert_tree *exclude) +load_trusted(void) { unsigned int i, n; int ret; /* load external trusted certs */ - for (i = n = 0; all && trusted_paths[i] != NULL; i++) { - ret = read_certs(trusted_paths[i], &trusted, exclude); + for (i = n = 0; trusted_paths[i] != NULL; i++) { + ret = read_certs(trusted_paths[i], &trusted, &untrusted); if (ret > 0) n += ret; } - /* load installed trusted certs */ - ret = read_certs(trusted_dest, &trusted, exclude); - if (ret > 0) - n += ret; - info("%d trusted certificates found", n); return (n); } @@ -663,24 +658,19 @@ load_trusted(bool all, struct cert_tree *exclude) * Returns the number of certificates loaded. */ static unsigned int -load_untrusted(bool all) +load_untrusted(void) { char *path; unsigned int i, n; int ret; /* load external untrusted certs */ - for (i = n = 0; all && untrusted_paths[i] != NULL; i++) { + for (i = n = 0; untrusted_paths[i] != NULL; i++) { ret = read_certs(untrusted_paths[i], &untrusted, NULL); if (ret > 0) n += ret; } - /* load installed untrusted certs */ - ret = read_certs(untrusted_dest, &untrusted, NULL); - if (ret > 0) - n += ret; - /* load legacy untrusted certs */ path = expand_path(LEGACY_PATH); ret = read_certs(path, &untrusted, NULL); @@ -796,8 +786,8 @@ certctl_list(int argc, char **argv __unused) { if (argc > 1) usage(); - /* load trusted certificates */ - load_trusted(false, NULL); + /* load installed trusted certificates */ + read_certs(trusted_dest, &trusted, NULL); /* list them */ list_certs(&trusted); free_certs(&trusted); @@ -814,8 +804,8 @@ certctl_untrusted(int argc, char **argv __unused) { if (argc > 1) usage(); - /* load untrusted certificates */ - load_untrusted(false); + /* load installed untrusted certificates */ + read_certs(untrusted_dest, &untrusted, NULL); /* list them */ list_certs(&untrusted); free_certs(&untrusted); @@ -842,10 +832,10 @@ certctl_rehash(int argc, char **argv __unused) } /* load untrusted certs first */ - load_untrusted(true); + load_untrusted(); /* load trusted certs, excluding any that are already untrusted */ - load_trusted(true, &untrusted); + load_trusted(); /* save everything */ ret = save_all(); @@ -859,7 +849,8 @@ certctl_rehash(int argc, char **argv __unused) } /* - * Manually add one or more certificates to the list of trusted certificates. + * Manually add one or more certificates to the list of trusted + * certificates. * * Returns 0 on success and -1 on failure. */ @@ -875,10 +866,10 @@ certctl_trust(int argc, char **argv) usage(); /* load untrusted certs first */ - load_untrusted(true); + load_untrusted(); /* load trusted certs, excluding any that are already untrusted */ - load_trusted(true, &untrusted); + load_trusted(); /* now load the additional trusted certificates */ n = 0; @@ -891,9 +882,9 @@ certctl_trust(int argc, char **argv) warnx("no new trusted certificates found"); free_certs(&untrusted); free_certs(&trusted); - free_certs(&extra); return (0); } + warnx("%u new trusted certificate%s found", n, n > 1 ? "s" : ""); /* * For each new trusted cert, move it from the extra list to the @@ -906,10 +897,16 @@ certctl_trust(int argc, char **argv) RB_INSERT(cert_tree, &trusted, cert); if ((other = RB_FIND(cert_tree, &untrusted, cert)) != NULL) { warnx("%s was previously untrusted", cert->name); + warnx("source of untrust: %s", other->path); RB_REMOVE(cert_tree, &untrusted, other); free_cert(other); } } + warnx("This operation is not persistent. To persistently add"); + warnx("trusted certificates to the system store, copy them to"); + warnx("one of these directories, then run `certctl rehash`:"); + for (i = 0; trusted_paths[i] != NULL; i++) + warnx(" %s", trusted_paths[i]); /* save everything */ ret = save_all(); @@ -929,6 +926,8 @@ certctl_trust(int argc, char **argv) static int certctl_untrust(int argc, char **argv) { + struct cert_tree extra = RB_INITIALIZER(&extra); + struct cert *cert, *other, *tmp; unsigned int n; int i, ret; @@ -936,23 +935,47 @@ certctl_untrust(int argc, char **argv) usage(); /* load untrusted certs first */ - load_untrusted(true); + load_untrusted(); + + /* load trusted certs, excluding any that are already untrusted */ + load_trusted(); /* now load the additional untrusted certificates */ n = 0; for (i = 1; i < argc; i++) { - ret = read_cert(argv[i], &untrusted, NULL); + ret = read_cert(argv[i], &extra, NULL); if (ret > 0) n += ret; } if (n == 0) { warnx("no new untrusted certificates found"); free_certs(&untrusted); + free_certs(&trusted); return (0); } + warnx("%u new untrusted certificate%s found", n, n > 1 ? "s" : ""); - /* load trusted certs, excluding any that are already untrusted */ - load_trusted(true, &untrusted); + /* + * For each new untrusted cert, move it from the extra list to the + * untrusted list, then check if a matching certificate exists on + * the trusted list. If that is the case, warn the user, then + * remove the matching certificate from the trusted list. + */ + RB_FOREACH_SAFE(cert, cert_tree, &extra, tmp) { + RB_REMOVE(cert_tree, &extra, cert); + RB_INSERT(cert_tree, &untrusted, cert); + if ((other = RB_FIND(cert_tree, &trusted, cert)) != NULL) { + warnx("%s was previously trusted", cert->name); + warnx("source of trust: %s", other->path); + RB_REMOVE(cert_tree, &trusted, other); + free_cert(other); + } + } + warnx("This operation is not persistent. To persistently add"); + warnx("untrusted certificates to the system store, copy them to"); + warnx("one of these directories, then run `certctl rehash`:"); + for (i = 0; untrusted_paths[i] != NULL; i++) + warnx(" %s", untrusted_paths[i]); /* save everything */ ret = save_all(); diff --git a/usr.sbin/certctl/tests/certctl_test.sh b/usr.sbin/certctl/tests/certctl_test.sh index 74749db0b3f5..133d65854c42 100644 --- a/usr.sbin/certctl/tests/certctl_test.sh +++ b/usr.sbin/certctl/tests/certctl_test.sh @@ -271,7 +271,8 @@ untrust_body() crtfile=usr/share/certs/trusted/${crtname}.crt check_trusted "${crtname}" check_in_bundle ${crtfile} - atf_check certctl untrust "${crtfile}" + atf_check -e match:"1 new untrusted" \ + certctl untrust "${crtfile}" check_untrusted "${crtname}" check_not_in_bundle ${crtfile} } |
