diff options
author | Ludovic Courtès <ludo@gnu.org> | 2013-12-30 23:18:52 +0100 |
---|---|---|
committer | Ludovic Courtès <ludo@gnu.org> | 2013-12-30 23:18:52 +0100 |
commit | f82cc5fdbe62d835d884f2be2289c95da478da25 (patch) | |
tree | f2daeed33b1e041f53ad0f9e3eb70d4b9466c2d5 | |
parent | 554f26ece3c6e3fb04d8069e6be1095e622a97c5 (diff) |
archive: Add '--authorize'.
* guix/scripts/archive.scm (authorize-key): New procedure.
(guix-archive): Call it when OPTS contains 'authorize-key'.
* tests/guix-archive.sh: Add test with invalid public key.
* guix/pki.scm: Export '%acl-file'.
* doc/guix.texi (Invoking guix archive): Make it clear that '--import'
works only with authorized keys. Document '--authorize'.
-rw-r--r-- | doc/guix.texi | 20 | ||||
-rw-r--r-- | guix/pki.scm | 1 | ||||
-rw-r--r-- | guix/scripts/archive.scm | 28 | ||||
-rw-r--r-- | tests/guix-archive.sh | 3 |
4 files changed, 50 insertions, 2 deletions
diff --git a/doc/guix.texi b/doc/guix.texi index ec529346c7..9976024c06 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -942,7 +942,8 @@ Archives are stored in the ``Nix archive'' or ``Nar'' format, which is comparable in spirit to `tar'. When exporting, the daemon digitally signs the contents of the archive, and that digital signature is appended. When importing, the daemon verifies the signature and rejects -the import in case of an invalid signature. +the import in case of an invalid signature or if the signing key is not +authorized. @c FIXME: Add xref to daemon doc about signatures. The main options are: @@ -955,9 +956,11 @@ resulting archive to the standard output. @item --import Read an archive from the standard input, and import the files listed therein into the store. Abort if the archive has an invalid digital -signature. +signature, or if it is signed by a public key not among the authorized +keys (see @code{--authorize} below.) @item --generate-key[=@var{parameters}] +@cindex signing, archives Generate a new key pair for the daemons. This is a prerequisite before archives can be exported with @code{--export}. Note that this operation usually takes time, because it needs to gather enough entropy to @@ -970,6 +973,19 @@ is a 4096-bit RSA key. Alternately, @var{parameters} can specify @code{genkey} parameters suitable for Libgcrypt (@pxref{General public-key related Functions, @code{gcry_pk_genkey},, gcrypt, The Libgcrypt Reference Manual}). + +@item --authorize +@cindex authorizing, archives +Authorize imports signed by the public key passed on standard input. +The public key must be in ``s-expression advanced format''---i.e., the +same format as the @file{signing-key.pub} file. + +The list of authorized keys is kept in the human-editable file +@file{/etc/guix/acl}. The file contains +@url{http://people.csail.mit.edu/rivest/Sexp.txt, ``advanced-format +s-expressions''} and is structured as an access-control list in the +@url{http://theworld.com/~cme/spki.txt, Simple Public-Key Infrastructure +(SPKI)}. @end table To export store files as an archive to the standard output, run: diff --git a/guix/pki.scm b/guix/pki.scm index 759cd040e9..dc8139fbc9 100644 --- a/guix/pki.scm +++ b/guix/pki.scm @@ -24,6 +24,7 @@ #:use-module (rnrs io ports) #:export (%public-key-file %private-key-file + %acl-file current-acl public-keys->acl acl->public-keys diff --git a/guix/scripts/archive.scm b/guix/scripts/archive.scm index a9e4155393..66000435b4 100644 --- a/guix/scripts/archive.scm +++ b/guix/scripts/archive.scm @@ -32,6 +32,7 @@ #:use-module (srfi srfi-37) #:use-module (guix scripts build) #:use-module (guix scripts package) + #:use-module (rnrs io ports) #:export (guix-archive)) @@ -111,6 +112,9 @@ Export/import one or more packages from/to the store.\n")) (lambda args (leave (_ "invalid key generation parameters: ~s~%") arg))))) + (option '("authorize") #f #f + (lambda (opt name arg result) + (alist-cons 'authorize #t result))) (option '(#\S "source") #f #f (lambda (opt name arg result) @@ -256,6 +260,28 @@ this may take time...~%")) ;; Make the public key readable by everyone. (chmod %public-key-file #o444))) +(define (authorize-key) + "Authorize imports signed by the public key passed as an advanced sexp on +the input port." + (define (read-key) + (catch 'gcry-error + (lambda () + (string->canonical-sexp (get-string-all (current-input-port)))) + (lambda (key err) + (leave (_ "failed to read public key: ~a: ~a~%") + (error-source err) (error-string err))))) + + (let ((key (read-key)) + (acl (current-acl))) + (unless (eq? 'public-key (canonical-sexp-nth-data key 0)) + (leave (_ "s-expression does not denote a public key~%"))) + + ;; Add KEY to the ACL and write that. + (let ((acl (public-keys->acl (cons key (acl->public-keys acl))))) + (with-atomic-file-output %acl-file + (lambda (port) + (display (canonical-sexp->string acl) port)))))) + (define (guix-archive . args) (define (parse-options) ;; Return the alist of option values. @@ -274,6 +300,8 @@ this may take time...~%")) (cond ((assoc-ref opts 'generate-key) => generate-key-pair) + ((assoc-ref opts 'authorize) + (authorize-key)) (else (let ((store (open-connection))) (cond ((assoc-ref opts 'export) diff --git a/tests/guix-archive.sh b/tests/guix-archive.sh index ef04835469..3ac618ae33 100644 --- a/tests/guix-archive.sh +++ b/tests/guix-archive.sh @@ -43,3 +43,6 @@ guix archive --import < "$archive" 2>&1 | grep "import.*guile-bootstrap" if guix archive something-that-does-not-exist then false; else true; fi + +if echo foo | guix archive --authorize +then false; else true; fi |