Hi Divan,

Divan Santana <di...@santanas.co.za> writes:

> Joshua Branson <jbra...@fastmail.com> writes:
>
>> Divan Santana <di...@santanas.co.za> writes:
>>
>>> Hi Guix :)
>>>
>>> How does one import a root certificate for GuixSD?
>>
>> This probably isn't helpful, but what is a root certificate?
>
> https://en.wikipedia.org/wiki/Root_certificate
>
> In cryptography and computer security, a root certificate is a public
> key certificate that identifies a root certificate authority (CA).[1]
> Root certificates are self-signed and form the basis of an X.509-based
> public key infrastructure (PKI).
>
> So in my case, I have a root CA certificate for our organisition and
> many internal sites have a certificate issued from this CA.

I intended to write a blog post about this very subject for the Guix
blog, but I haven't gotten around to it yet.  In short, to do what you
want, you can create package definitions like the following, and then
add them to the "packages" field of your operating system declaration:

--8<---------------cut here---------------start------------->8---
(define-module (my packages)
  #:use-module (guix packages)
  #:use-module (guix licenses)
  #:use-module (guix build-system trivial)
  #:use-module (guix gexp))

;; This example aggregates many certificates from a local directory, but
;; the same principle could be used to aggregate certificates from, say,
;; a remote Git repository that your company maintains.
(define-public my-ca-certificates
  (package
   (name "my-ca-certificates")
   (version "1")
   (source (local-file "/path/to/directory/containing/my/certs"
                       #:recursive? #t))
   (home-page "https://www.example.com";)
   (license agpl3+)
   (build-system trivial-build-system)
   (arguments
    `(#:modules
      ((guix build utils))
      #:builder
      (begin
        (use-modules (guix build utils)
                     (srfi srfi-1)
                     (srfi srfi-26)
                     (ice-9 ftw))
        (let* ((ca-certificates (assoc-ref %build-inputs "source"))
               (crt-suffix ".crt")
               (is-certificate? (cut string-suffix? crt-suffix <>))
               (certificates (filter is-certificate?
                                     (scandir ca-certificates)))
               (out (assoc-ref %outputs "out"))
               (certificate-directory (string-append out
                                                     "/etc/ssl/certs"))
               (openssl (string-append (assoc-ref %build-inputs
                                                  "openssl")
                                       "/bin/openssl")))
          (mkdir-p certificate-directory)
          ;; When this package is installed into a profile, any files in the
          ;; package output's etc/ssl/certs directory ending in ".pem" will
          ;; also be put into a ca-certificates.crt bundle.  In the case of a
          ;; system profile, this bundle will be made available to the system
          ;; at activation time.  See the profile hooks defined in (guix
          ;; profiles) and the etc-service-type define in (gnu services) for
          ;; details.
          (for-each
           ;; Ensure the certificate is in an appropriate format.
           (lambda (certificate)
             (invoke
              openssl "x509"
              "-in" (string-append ca-certificates "/" certificate)
              "-outform" "PEM"
              "-out" (string-append
                      certificate-directory "/"
                      (basename certificate crt-suffix) ".pem")))
           certificates)
          #t))))
   (inputs
    `(("openssl" ,openssl)))
   (synopsis "My certificate authority certificates")
   (description synopsis)))

(define-public my-ca-certificate
  (package
   (name "my-ca-certificate")
   (version "1")
   ;; You might also be able to set the source to #f and just embed the
   ;; certificate directly into the builder below.
   (source (plain-file (string-append name ".pem") "\
-----BEGIN CERTIFICATE-----
Put your cert here.
-----END CERTIFICATE-----
"))
   (home-page "https://www.example.com";)
   (license agpl3+)
   (build-system trivial-build-system)
   (arguments
    `(#:modules
      ((guix build utils))
      #:builder
      (begin
        (use-modules (guix build utils))
        (let* ((my-certificate (assoc-ref %build-inputs "source"))
               (out (assoc-ref %outputs "out"))
               (cert-dir (string-append out "/etc/ssl/certs")))
          (mkdir-p cert-dir)
          (copy-file my-certificate (string-append cert-dir "/" ,name ".pem"))
          #t))))
   (synopsis "My certificate authority certificate")
   (description synopsis)))
--8<---------------cut here---------------end--------------->8---

When you add a package like the above to your operating system
declaration's "packages" field and reconfigure your system, you will
install the certificates system-wide.

In GuixSD, when you build a new system generation, there is a profile
hook that essentially collects all the certificates that you would find
in the $PROFILE/etc/ssl/certs directory and bundles them up into the
single $PROFILE/etc/ssl/certs/ca-certificates.crt file (here, $PROFILE
refers to the system profile, i.e.  the one that the
/run/current-system/profile symlink points to).  When it's done, you
will have a copy of your certificate in an individual file at
$PROFILE/etc/ssl/certs/your-cert.pem, and also in the bundle at
$PROFILE/etc/ssl/certs/ca-certificates.crt.  This is necessary because
some software needs the bundle:

https://lists.gnu.org/archive/html/guix-devel/2015-02/msg00429.html

Anyway, to install your certificates system-wide, you "just" have to
write a package definition that deposits your certificates in the
$OUT/etc/ssl/certs directory (where $OUT is the output path of the
package).  I think the files containing the certificates also need to
end in the suffix ".pem" in order for this specific profile hook to
work.  See the profile hook source code for details (in
guix/profiles.scm).

So, you can add your certificates.  But it relies on the behavior of a
profile hook that (I think) isn't yet discussed in the manual.  It
works, which is great, but I think it would be better if we provided a
first-class way to configure this in the operating system declaration.
Perhaps we need an "x509-certificates" service which one can extend with
certificates, origins, or packages that build certificates.

Finally, keep in mind that even if you add your certificate to the
system like this, not all software will use it.  For example, IceCat
ignores the system certificates (because that's what Firefox does, and
IceCat is a derivative of Firefox); instead, it maintains its own trust
database.  Java is similar.  For many programs, though, adding
certificates as above is sufficient.

-- 
Chris

Attachment: signature.asc
Description: PGP signature

Reply via email to