guix-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Using G-Expressions for public keys (substitutes and possibly more)


From: Jelle Licht
Subject: Re: Using G-Expressions for public keys (substitutes and possibly more)
Date: Sun, 21 Nov 2021 01:12:27 +0100

Hey folks,

Liliana Marie Prikler <liliana.prikler@gmail.com> writes:

> Hi Ludo,
>
> Am Donnerstag, den 21.10.2021, 22:13 +0200 schrieb Ludovic Courtès:
>> Hi!
>> 
>> Liliana Marie Prikler <liliana.prikler@gmail.com> skribis:
>> 
>> > let's say I wanted to add my own substitute server to my
>> > config.scm. 
>> > At the time of writing, I would have to add said server's public
>> > key to
>> > the authorized-keys of my guix-configuration like so:
>> >   (cons* (local-file "my-key.pub") %default-authorized-guix-keys)
>> > or similarily with append.  This local-file incantation is however
>> > pretty weak.  It changes based on the current working directory and
>> > even if I were to use an absolute path, I'd have to copy both that
>> > file
>> > and the config.scm to a new machine were I to use the same
>> > configuration there as well.
>> 
>> Note that you could use ‘plain-file’ instead of ‘local-file’ and
>> inline the key canonical sexp in there.
> Yes, but for that I'd have to either write a (multi-line) string
> directly, which visibly "breaks" indentation of the rest of the file,
> or somehow generate a string which adds at least one layer of
> indentation.  The former is imo unacceptable, the latter merely
> inconvenient.

Would some arbitrary s-expression be a workable solution? See below for
an example for what I understood was your current use-case.

>> > However, it turns out that the format for said key files is some
>> > actually pretty readable Lisp-esque stuff.  For instance, an ECC
>> > key reads like
>> >   (public-key (ecc (curve CURVE) (q #Q#)))
>> > with spaces omitted for simplicity.
>> > Were it not for the (q #Q#) bit, we could construct it using
>> > scheme-file.  In fact, it is so simple that in my local config I
>> > now do exactly that.
>> 
>> Yeah it’s frustrating that canonical sexps are almost, but not quite,
>> Scheme sexps.  :-)
>> 
>> (gcrypt pk-crypto) has a ‘canonical-sexp->sexp’ procedure:
>> 
>> --8<---------------cut here---------------start------------->8---
>> scheme@(guile-user)> ,use(gcrypt pk-crypto)
>> scheme@(guile-user)> ,use(rnrs io ports)
>> scheme@(guile-user)> (string->canonical-sexp
>>                    (call-with-input-file
>> "etc/substitutes/ci.guix.info.pub"
>>                      get-string-all))
>> $18 = #<canonical-sexp 7fce7f4e8b40 | 15d96a0>
>> scheme@(guile-user)> ,pp (canonical-sexp->sexp $18)
>> $19 = (public-key
>>   (ecc (curve Ed25519)
>>        (q #vu8(141 21 111 41 93 36 176 217 168 111 165 116 26 132 15
>> 242 210 79 96 247 182 196 19 72 20 173 85 98 89 113 179 148))))
>> --8<---------------cut here---------------end--------------->8---
>> 
>> > (define-record-type* <ecc-key> ...)
>> > (define-gexp-compiler (ecc-key-compiler (ecc-key <ecc-key>) ...)
>> > ...)
>> > 
>> > (ecc-key
>> >   (name "my-key.pub")
>> >   (curve 'Ed25519)
>> >   (q "ABCDE..."))
>> > 
>> > Could/should we support such formats out of the box?  WDYT?
>> 
>> With this approach, we’d end up mirroring all the canonical sexps
>> used by libgcrypt, which doesn’t sound great from a maintenance POV.
> Given that we can use canonical sexps, what about a single canonical-
> sexp compiler then?  I'd have to think about this a bit more when I
> have the time to, but having a way of writing the canonical sexp
> "directly" would imo be advantageous.

What about something such as the following?

--8<---------------cut here---------------start------------->8---
(use-modules (gcrypt base16)
             (gcrypt pk-crypto))

(define-record-type <canonical-sexp-wrapper>
  (canonical-sexp-wrapper name sexp)
  canonical-sexp-wrapper?
  (name canonical-sexp-wrapper-name)
  (sexp canonical-sexp-wrapper-sexp))

(define-gexp-compiler (canonical-sexp-wrapper-compiler
                       (wrapper <canonical-sexp-wrapper>) system target)
  (match wrapper
    (($ <canonical-sexp-wrapper> name sexp)
     (text-file name (canonical-sexp->string
                      (sexp->canonical-sexp sexp)) '()))))
--8<---------------cut here---------------end--------------->8---

This would still leave constructing your s-expression as an exercise to
the reader, which is definitely not amazing. In this specific instance,
I had to look at the output of canonical-sexp->sexp, which is of course
whatever the opposite of discoverable and good UX :).

For the Ed25519 key:
--8<---------------cut here---------------start------------->8---
(define my-public-key
  (canonical-sexp-wrapper
   "my-key.pub"
   `(public-key
     (ecc
      (curve Ed25519)
      (q ,(base16-string->bytevector
           (string-downcase
            "C9F307AE...")))))))
--8<---------------cut here---------------end--------------->8---

To improve on this, is one sexp-based-gexp-compiler + N helper functions
to construct the most-used value types a direction worth exploring?

 - Jelle



reply via email to

[Prev in Thread] Current Thread [Next in Thread]