#### Issue Description Attempt to load a certificate bundle into 389ds using dsconf fails, as dsconf only appears to handle single certificates at a time. Because virtually no systems work with individual certs, this renders dsconf useless for importing CA certs. certutil from NSS appears to have the same bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1664816 #### Package Version and Platform RHEL8 latest. #### Steps to reproduce 1. [root@gatekeeper gatekeeper]# dsconf gatekeeper security ca-certificate add --file /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem 2. 3. #### Actual results usage: dsconf instance security ca-certificate add [-h] --file FILE --name NAME dsconf instance security ca-certificate add: error: the following arguments are required: --name Failure - no certs are installed. #### Expected results All certificates in the bundle installed.
"dsconf security" is just a wrapper for certutil. So if certutl can not do it, then dsconf definitely can not either. There are also certificate tasks using dsctl, does that exhibit the same behavior? Probably but would be good to know: # dsctl localhost tls import-server-cert ...
No luck: [root@gatekeeper ~]# dsctl gatekeeper tls import-ca /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem usage: dsctl [instance] tls import-ca [-h] cert_path nickname dsctl [instance] tls import-ca: error: the following arguments are required: nickname Adding a nickname means only one cert is imported, all others are ignored: [root@gatekeeper ~]# dsctl gatekeeper tls import-ca /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem test [root@gatekeeper ~]# dsctl gatekeeper tls list-ca test
Looks like the missing piece of dsctl and dsconf is to parse each certificate in the incoming file one at a time, and then pass each certificate to NSS. Another option is to fix this is certutil - remove the restriction that only one certificate can be imported at a time.
(In reply to Graham Leggett from comment #3) > Looks like the missing piece of dsctl and dsconf is to parse each > certificate in the incoming file one at a time, and then pass each > certificate to NSS. > > Another option is to fix this is certutil - remove the restriction that only > one certificate can be imported at a time. Yeah that should be doable. Changing bug to RFE, and adding acks...
related upstream ticket: https://github.com/389ds/389-ds-base/issues/5162
Fixed CLI tools to allow CA certificate PEM file bundles.
Automated test passed: ========================================== test session starts =========================================== platform linux -- Python 3.9.16, pytest-6.2.2, py-1.10.0, pluggy-0.13.1 -- /usr/bin/python3 cachedir: .pytest_cache 389-ds-base: 2.2.6-1.module+el9dsrv+17949+63c5b04e nss: 3.79.0-14.el9_0 nspr: 4.34.0-14.el9_0 openldap: 2.6.2-3.el9 cyrus-sasl: not installed FIPS: disabled rootdir: /root/ds/dirsrvtests, configfile: pytest.ini collected 1 item dirsrvtests/tests/suites/clu/ca_cert_bundle_test.py::test_ca_cert_bundle PASSED [100%] =========================================== 1 passed in 38.20s =========================================== Basic functionality works (loading a CA bundle is successful), but I found minor issues: [1] Importing the same bundle under a different name is reported as successful, but the certificates are not actually imported: # dsconf standalone1 security ca-certificate add --file bundle.pem --name CA1 CA2 Successfully added CA certificate (CA1) Successfully added CA certificate (CA2) # certutil -d /etc/dirsrv/slapd-standalone1/ -L Certificate Nickname Trust Attributes SSL,S/MIME,JAR/XPI CA1 CT,, CA2 CT,, # dsconf standalone1 security ca-certificate add --file bundle.pem --name CA1 CA2 Error: Certificate already exists with the same name (CA1) # dsconf standalone1 security ca-certificate add --file bundle.pem --name CA3 CA4 Successfully added CA certificate (CA3) Successfully added CA certificate (CA4) # certutil -d /etc/dirsrv/slapd-standalone1/ -L Certificate Nickname Trust Attributes SSL,S/MIME,JAR/XPI CA1 CT,, CA2 CT,, This issue comes from certutil, that doesn't report a non-zero exit code if the certificate is already in the database. # /usr/bin/certutil -A -d /etc/dirsrv/slapd-standalone1 -n CA999 -t CT,, -i bundle.pem-1 -a -f /etc/dirsrv/slapd-standalone1/pwdfile.txt # echo $? 0 We should check if the certificate with the given name was imported. And if it's missing from the list of nicknames in the database and certutil's exit code was 0, print a better message. [2] dsconf doesn't cleanup temporary files from the current working directory: # ls -1 bundle* bundle.pem bundle.pem-0 bundle.pem-1 [3] dsconf doesn't check if the imported certificate is actually a CA certificate. If a bundle contains a server certificate, it is also imported with CT,, trust flags. We can check for key usage (cert sign) and basic constraints (CA) in the cert, and import it as CA only if the check is successful. I think [1] and [2] should be fixed, and [3] is up for debate, because it might introduce additional dependency (python-cryptography) that won't be useful in 99% cases. Moving to ASSIGNED.
As for [3] not sure how to tell if a cert is "server" or "ca" cert. I always thought it was just how you assign the trust flags that differentiated between the two (but I could definitely be wrong). The tooling assumes the user knows how they want to use the cert (server vs CA).
Created attachment 1943332 [details] check_cert.py It can be done something like this using python-cryptography.
If we do not want to add new dependency, we can also check for the "Usages: Certificate Signing" in certutil -d ... -n certName output But before taking a decision we have to double check (I am not sure that the certificate extensions are mandatory (especially when the "verify cert" flag is disabled.) Maybe we should rather open a warning window and asking the user if we should proceed or not
Automated test passed: ============================================================= test session starts ============================================================= platform linux -- Python 3.9.16, pytest-6.2.2, py-1.10.0, pluggy-0.13.1 -- /usr/bin/python3 cachedir: .pytest_cache 389-ds-base: 2.2.7-1.module+el9dsrv+18376+e226feec nss: 3.79.0-18.el9_1 nspr: 4.34.0-18.el9_1 openldap: 2.6.2-3.el9 cyrus-sasl: not installed FIPS: disabled rootdir: /root/ds/dirsrvtests, configfile: pytest.ini collected 1 item dirsrvtests/tests/suites/clu/ca_cert_bundle_test.py::test_ca_cert_bundle PASSED [100%] ============================================================= 1 passed in 16.64s ============================================================= Additional test cases from https://bugzilla.redhat.com/show_bug.cgi?id=1878808#c11 [1] Importing the same bundle under a different name is reported as successful, but the certificates are not actually imported: [root@localhost ds]# certutil -d /etc/dirsrv/slapd-standalone1/ -L Certificate Nickname Trust Attributes SSL,S/MIME,JAR/XPI CA_CERT_1 CT,, CA_CERT_2 CT,, [root@localhost ds]# dsconf standalone1 security ca-certificate add --file /tmp/ca-bundle.pem --name CA3 CA4 Successfully added CA certificate (CA3) Successfully added CA certificate (CA4) [root@localhost ds]# certutil -d /etc/dirsrv/slapd-standalone1/ -L Certificate Nickname Trust Attributes SSL,S/MIME,JAR/XPI CA_CERT_1 CT,, CA_CERT_2 CT,, [2] Fixed - temporary files are not present anymore. [3] Fixed - Non-CA certificates are not imported: # dsconf standalone1 security ca-certificate add --file Server-Cert.crt --name Server Error: Certificate (Server) is not a CA certificate Since [1] is not fixed, moving to ASSIGNED.
> [1] Importing the same bundle under a different name is reported as successful, but the certificates are not actually imported: > [root@localhost ds]# certutil -d /etc/dirsrv/slapd-standalone1/ -L I think this is an issue with certutil, where if the certificate(s) itself are the same as what's in NSS db it treats it as a no-op (idempotent sort of). Only if the certs in the bundle are different than what's in the NSS db will it perform the op. This might require a lot of hoops to jump through to try and work around certutil's behavior...
I'm facing another issue with CA certificates. I have a self-signed certificate generated by openssl: openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -out my.crt -keyout my.key I'm trying to import it, but it fails with an error message: # dsconf localhost security ca-certificate add --name=myca --file=my.crt Error: No <ObjectIdentifier(oid=2.5.29.15, name=keyUsage)> extension was found My CA cert doesn't have key usage specified, but has a basic constraint to be used as a CA cert. Turns out some of the CA certs from the system CA bundle also don't have key usage specified, and they fail to be imported. Maybe we shouldn't be that strict or provide a "force" option to import the CA cert anyway.
RN texted prepared in the DocText field. Moving to SME review
RN text was reviewed by Viktor, moving to a peer review
RN text was reviewed by a peer and release pending. Thanks, Masha!
Build tested: 389-ds-base-2.2.7-3.module+el9dsrv+18864+4949f8c5.x86_64 Issue in https://bugzilla.redhat.com/show_bug.cgi?id=1878808#c22 was addressed: # openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -out my.crt -keyout my.key # dsconf localhost security ca-certificate add --name=myca --file=my.crt Successfully added CA certificate (myca) # certutil -d /etc/dirsrv/slapd-localhost/ -L | grep myca myca CT,, Marking as VERIFIED.
Since the problem described in this bug report should be resolved in a recent advisory, it has been closed with a resolution of ERRATA. For information on the advisory (redhat-ds:12 bug fix and enhancement update), and where to find the updated files, follow the link below. If the solution does not work for you, open a new bug report. https://access.redhat.com/errata/RHBA-2023:3344