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'.
This commit is contained in:
Ludovic Courtès 2013-12-30 23:18:52 +01:00
parent 554f26ece3
commit f82cc5fdbe
4 changed files with 50 additions and 2 deletions

View file

@ -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:

View file

@ -24,6 +24,7 @@ (define-module (guix pki)
#:use-module (rnrs io ports)
#:export (%public-key-file
%private-key-file
%acl-file
current-acl
public-keys->acl
acl->public-keys

View file

@ -32,6 +32,7 @@ (define-module (guix scripts archive)
#: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 @@ (define %options
(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 @@ (define (generate-key-pair parameters)
;; 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 @@ (define (parse-options)
(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)

View file

@ -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