summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLudovic Courtès <ludo@gnu.org>2013-12-30 23:18:52 +0100
committerLudovic Courtès <ludo@gnu.org>2013-12-30 23:18:52 +0100
commitf82cc5fdbe62d835d884f2be2289c95da478da25 (patch)
treef2daeed33b1e041f53ad0f9e3eb70d4b9466c2d5
parent554f26ece3c6e3fb04d8069e6be1095e622a97c5 (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.texi20
-rw-r--r--guix/pki.scm1
-rw-r--r--guix/scripts/archive.scm28
-rw-r--r--tests/guix-archive.sh3
4 files changed, 50 insertions, 2 deletions
diff --git a/doc/guix.texi b/doc/guix.texi
index ec529346c7a..9976024c06e 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
942comparable in spirit to `tar'. When exporting, the daemon digitally 942comparable in spirit to `tar'. When exporting, the daemon digitally
943signs the contents of the archive, and that digital signature is 943signs the contents of the archive, and that digital signature is
944appended. When importing, the daemon verifies the signature and rejects 944appended. When importing, the daemon verifies the signature and rejects
945the import in case of an invalid signature. 945the import in case of an invalid signature or if the signing key is not
946authorized.
946@c FIXME: Add xref to daemon doc about signatures. 947@c FIXME: Add xref to daemon doc about signatures.
947 948
948The main options are: 949The main options are:
@@ -955,9 +956,11 @@ resulting archive to the standard output.
955@item --import 956@item --import
956Read an archive from the standard input, and import the files listed 957Read an archive from the standard input, and import the files listed
957therein into the store. Abort if the archive has an invalid digital 958therein into the store. Abort if the archive has an invalid digital
958signature. 959signature, or if it is signed by a public key not among the authorized
960keys (see @code{--authorize} below.)
959 961
960@item --generate-key[=@var{parameters}] 962@item --generate-key[=@var{parameters}]
963@cindex signing, archives
961Generate a new key pair for the daemons. This is a prerequisite before 964Generate a new key pair for the daemons. This is a prerequisite before
962archives can be exported with @code{--export}. Note that this operation 965archives can be exported with @code{--export}. Note that this operation
963usually takes time, because it needs to gather enough entropy to 966usually 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
970@code{genkey} parameters suitable for Libgcrypt (@pxref{General 973@code{genkey} parameters suitable for Libgcrypt (@pxref{General
971public-key related Functions, @code{gcry_pk_genkey},, gcrypt, The 974public-key related Functions, @code{gcry_pk_genkey},, gcrypt, The
972Libgcrypt Reference Manual}). 975Libgcrypt Reference Manual}).
976
977@item --authorize
978@cindex authorizing, archives
979Authorize imports signed by the public key passed on standard input.
980The public key must be in ``s-expression advanced format''---i.e., the
981same format as the @file{signing-key.pub} file.
982
983The list of authorized keys is kept in the human-editable file
984@file{/etc/guix/acl}. The file contains
985@url{http://people.csail.mit.edu/rivest/Sexp.txt, ``advanced-format
986s-expressions''} and is structured as an access-control list in the
987@url{http://theworld.com/~cme/spki.txt, Simple Public-Key Infrastructure
988(SPKI)}.
973@end table 989@end table
974 990
975To export store files as an archive to the standard output, run: 991To export store files as an archive to the standard output, run:
diff --git a/guix/pki.scm b/guix/pki.scm
index 759cd040e95..dc8139fbc9a 100644
--- a/guix/pki.scm
+++ b/guix/pki.scm
@@ -24,6 +24,7 @@
24 #:use-module (rnrs io ports) 24 #:use-module (rnrs io ports)
25 #:export (%public-key-file 25 #:export (%public-key-file
26 %private-key-file 26 %private-key-file
27 %acl-file
27 current-acl 28 current-acl
28 public-keys->acl 29 public-keys->acl
29 acl->public-keys 30 acl->public-keys
diff --git a/guix/scripts/archive.scm b/guix/scripts/archive.scm
index a9e41553930..66000435b49 100644
--- a/guix/scripts/archive.scm
+++ b/guix/scripts/archive.scm
@@ -32,6 +32,7 @@
32 #:use-module (srfi srfi-37) 32 #:use-module (srfi srfi-37)
33 #:use-module (guix scripts build) 33 #:use-module (guix scripts build)
34 #:use-module (guix scripts package) 34 #:use-module (guix scripts package)
35 #:use-module (rnrs io ports)
35 #:export (guix-archive)) 36 #:export (guix-archive))
36 37
37 38
@@ -111,6 +112,9 @@ Export/import one or more packages from/to the store.\n"))
111 (lambda args 112 (lambda args
112 (leave (_ "invalid key generation parameters: ~s~%") 113 (leave (_ "invalid key generation parameters: ~s~%")
113 arg))))) 114 arg)))))
115 (option '("authorize") #f #f
116 (lambda (opt name arg result)
117 (alist-cons 'authorize #t result)))
114 118
115 (option '(#\S "source") #f #f 119 (option '(#\S "source") #f #f
116 (lambda (opt name arg result) 120 (lambda (opt name arg result)
@@ -256,6 +260,28 @@ this may take time...~%"))
256 ;; Make the public key readable by everyone. 260 ;; Make the public key readable by everyone.
257 (chmod %public-key-file #o444))) 261 (chmod %public-key-file #o444)))
258 262
263(define (authorize-key)
264 "Authorize imports signed by the public key passed as an advanced sexp on
265the input port."
266 (define (read-key)
267 (catch 'gcry-error
268 (lambda ()
269 (string->canonical-sexp (get-string-all (current-input-port))))
270 (lambda (key err)
271 (leave (_ "failed to read public key: ~a: ~a~%")
272 (error-source err) (error-string err)))))
273
274 (let ((key (read-key))
275 (acl (current-acl)))
276 (unless (eq? 'public-key (canonical-sexp-nth-data key 0))
277 (leave (_ "s-expression does not denote a public key~%")))
278
279 ;; Add KEY to the ACL and write that.
280 (let ((acl (public-keys->acl (cons key (acl->public-keys acl)))))
281 (with-atomic-file-output %acl-file
282 (lambda (port)
283 (display (canonical-sexp->string acl) port))))))
284
259(define (guix-archive . args) 285(define (guix-archive . args)
260 (define (parse-options) 286 (define (parse-options)
261 ;; Return the alist of option values. 287 ;; Return the alist of option values.
@@ -274,6 +300,8 @@ this may take time...~%"))
274 (cond ((assoc-ref opts 'generate-key) 300 (cond ((assoc-ref opts 'generate-key)
275 => 301 =>
276 generate-key-pair) 302 generate-key-pair)
303 ((assoc-ref opts 'authorize)
304 (authorize-key))
277 (else 305 (else
278 (let ((store (open-connection))) 306 (let ((store (open-connection)))
279 (cond ((assoc-ref opts 'export) 307 (cond ((assoc-ref opts 'export)
diff --git a/tests/guix-archive.sh b/tests/guix-archive.sh
index ef048354690..3ac618ae33c 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"
43 43
44if guix archive something-that-does-not-exist 44if guix archive something-that-does-not-exist
45then false; else true; fi 45then false; else true; fi
46
47if echo foo | guix archive --authorize
48then false; else true; fi