summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLudovic Courtès <ludo@gnu.org>2013-12-30 22:46:21 +0100
committerLudovic Courtès <ludo@gnu.org>2013-12-30 22:57:37 +0100
commit554f26ece3c6e3fb04d8069e6be1095e622a97c5 (patch)
tree4a64678b2f1c34c72a53e84264ca56a09b34c72c
parentdedb5d947ee2890524a5c6fb1343b3299e7731c3 (diff)
archive: Add '--generate-key'.
* guix/pk-crypto.scm (error-source, error-string): New procedures. * guix/pki.scm (%private-key-file): New variable. * guix/scripts/archive.scm (show-help): Document '--generate-key'. (%options): Add "generate-key". (generate-key-pair): New procedure. (guix-archive): Call 'generate-key' when OPTS contains a 'generate-key' pair. * doc/guix.texi (Setting Up the Daemon): Suggest generating a key pair. (Invoking guix archive): Document '--generate-key'.
-rw-r--r--doc/guix.texi22
-rw-r--r--guix/pk-crypto.scm18
-rw-r--r--guix/pki.scm4
-rw-r--r--guix/scripts/archive.scm74
4 files changed, 108 insertions, 10 deletions
diff --git a/doc/guix.texi b/doc/guix.texi
index afa7654d544..ec529346c7a 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -237,6 +237,14 @@ case, shared memory support is unavailable in the chroot environment.
237The workaround is to make sure that @file{/dev/shm} is directly a 237The workaround is to make sure that @file{/dev/shm} is directly a
238@code{tmpfs} mount point.}. 238@code{tmpfs} mount point.}.
239 239
240Finally, you may want to generate a key pair to allow the daemon to
241export signed archives of files from the store (@pxref{Invoking guix
242archive}):
243
244@example
245# guix archive --generate-key
246@end example
247
240Guix may also be used in a single-user setup, with @command{guix-daemon} 248Guix may also be used in a single-user setup, with @command{guix-daemon}
241running as an unprivileged user. However, to maximize non-interference 249running as an unprivileged user. However, to maximize non-interference
242of build processes, the daemon still needs to perform certain operations 250of build processes, the daemon still needs to perform certain operations
@@ -948,6 +956,20 @@ resulting archive to the standard output.
948Read an archive from the standard input, and import the files listed 956Read an archive from the standard input, and import the files listed
949therein into the store. Abort if the archive has an invalid digital 957therein into the store. Abort if the archive has an invalid digital
950signature. 958signature.
959
960@item --generate-key[=@var{parameters}]
961Generate a new key pair for the daemons. This is a prerequisite before
962archives can be exported with @code{--export}. Note that this operation
963usually takes time, because it needs to gather enough entropy to
964generate the key pair.
965
966The generated key pair is typically stored under @file{/etc/guix}, in
967@file{signing-key.pub} (public key) and @file{signing-key.sec} (private
968key, which must be kept secret.) When @var{parameters} is omitted, it
969is a 4096-bit RSA key. Alternately, @var{parameters} can specify
970@code{genkey} parameters suitable for Libgcrypt (@pxref{General
971public-key related Functions, @code{gcry_pk_genkey},, gcrypt, The
972Libgcrypt Reference Manual}).
951@end table 973@end table
952 974
953To export store files as an archive to the standard output, run: 975To export store files as an archive to the standard output, run:
diff --git a/guix/pk-crypto.scm b/guix/pk-crypto.scm
index d5b3eeb3508..50f709418c9 100644
--- a/guix/pk-crypto.scm
+++ b/guix/pk-crypto.scm
@@ -25,6 +25,8 @@
25 #:use-module (rnrs bytevectors) 25 #:use-module (rnrs bytevectors)
26 #:use-module (ice-9 match) 26 #:use-module (ice-9 match)
27 #:export (canonical-sexp? 27 #:export (canonical-sexp?
28 error-source
29 error-string
28 string->canonical-sexp 30 string->canonical-sexp
29 canonical-sexp->string 31 canonical-sexp->string
30 number->canonical-sexp 32 number->canonical-sexp
@@ -98,6 +100,22 @@
98 (set-pointer-finalizer! ptr finalize-canonical-sexp!)) 100 (set-pointer-finalizer! ptr finalize-canonical-sexp!))
99 sexp)) 101 sexp))
100 102
103(define error-source
104 (let* ((ptr (libgcrypt-func "gcry_strsource"))
105 (proc (pointer->procedure '* ptr (list int))))
106 (lambda (err)
107 "Return the error source (a string) for ERR, an error code as thrown
108along with 'gcry-error'."
109 (pointer->string (proc err)))))
110
111(define error-string
112 (let* ((ptr (libgcrypt-func "gcry_strerror"))
113 (proc (pointer->procedure '* ptr (list int))))
114 (lambda (err)
115 "Return the error description (a string) for ERR, an error code as
116thrown along with 'gcry-error'."
117 (pointer->string (proc err)))))
118
101(define string->canonical-sexp 119(define string->canonical-sexp
102 (let* ((ptr (libgcrypt-func "gcry_sexp_new")) 120 (let* ((ptr (libgcrypt-func "gcry_sexp_new"))
103 (proc (pointer->procedure int ptr `(* * ,size_t ,int)))) 121 (proc (pointer->procedure int ptr `(* * ,size_t ,int))))
diff --git a/guix/pki.scm b/guix/pki.scm
index 1ed84e55f00..759cd040e95 100644
--- a/guix/pki.scm
+++ b/guix/pki.scm
@@ -23,6 +23,7 @@
23 #:use-module (ice-9 match) 23 #:use-module (ice-9 match)
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 current-acl 27 current-acl
27 public-keys->acl 28 public-keys->acl
28 acl->public-keys 29 acl->public-keys
@@ -69,6 +70,9 @@ element in KEYS must be a canonical sexp with type 'public-key'."
69(define %public-key-file 70(define %public-key-file
70 (string-append %config-directory "/signing-key.pub")) 71 (string-append %config-directory "/signing-key.pub"))
71 72
73(define %private-key-file
74 (string-append %config-directory "/signing-key.sec"))
75
72(define (ensure-acl) 76(define (ensure-acl)
73 "Make sure the ACL file exists, and create an initialized one if needed." 77 "Make sure the ACL file exists, and create an initialized one if needed."
74 (unless (file-exists? %acl-file) 78 (unless (file-exists? %acl-file)
diff --git a/guix/scripts/archive.scm b/guix/scripts/archive.scm
index df538ed1b7d..a9e41553930 100644
--- a/guix/scripts/archive.scm
+++ b/guix/scripts/archive.scm
@@ -23,6 +23,8 @@
23 #:use-module (guix packages) 23 #:use-module (guix packages)
24 #:use-module (guix derivations) 24 #:use-module (guix derivations)
25 #:use-module (guix ui) 25 #:use-module (guix ui)
26 #:use-module (guix pki)
27 #:use-module (guix pk-crypto)
26 #:use-module (ice-9 match) 28 #:use-module (ice-9 match)
27 #:use-module (srfi srfi-1) 29 #:use-module (srfi srfi-1)
28 #:use-module (srfi srfi-11) 30 #:use-module (srfi srfi-11)
@@ -53,6 +55,9 @@ Export/import one or more packages from/to the store.\n"))
53 --import import from the archive passed on stdin")) 55 --import import from the archive passed on stdin"))
54 (newline) 56 (newline)
55 (display (_ " 57 (display (_ "
58 --generate-key[=PARAMETERS]
59 generate a key pair with the given parameters"))
60 (display (_ "
56 -e, --expression=EXPR build the package or derivation EXPR evaluates to")) 61 -e, --expression=EXPR build the package or derivation EXPR evaluates to"))
57 (display (_ " 62 (display (_ "
58 -S, --source build the packages' source derivations")) 63 -S, --source build the packages' source derivations"))
@@ -95,6 +100,17 @@ Export/import one or more packages from/to the store.\n"))
95 (option '("import") #f #f 100 (option '("import") #f #f
96 (lambda (opt name arg result) 101 (lambda (opt name arg result)
97 (alist-cons 'import #t result))) 102 (alist-cons 'import #t result)))
103 (option '("generate-key") #f #t
104 (lambda (opt name arg result)
105 (catch 'gcry-error
106 (lambda ()
107 (let ((params
108 (string->canonical-sexp
109 (or arg "(genkey (rsa (nbits 4:4096)))"))))
110 (alist-cons 'generate-key params result)))
111 (lambda args
112 (leave (_ "invalid key generation parameters: ~s~%")
113 arg)))))
98 114
99 (option '(#\S "source") #f #f 115 (option '(#\S "source") #f #f
100 (lambda (opt name arg result) 116 (lambda (opt name arg result)
@@ -204,7 +220,41 @@ resulting archive to the standard output port."
204 (if (or (assoc-ref opts 'dry-run?) 220 (if (or (assoc-ref opts 'dry-run?)
205 (build-derivations store drv)) 221 (build-derivations store drv))
206 (export-paths store files (current-output-port)) 222 (export-paths store files (current-output-port))
207 (leave (_ "unable to export the given packages"))))) 223 (leave (_ "unable to export the given packages~%")))))
224
225(define (generate-key-pair parameters)
226 "Generate a key pair with PARAMETERS, a canonical sexp, and store it in the
227right place."
228 (when (or (file-exists? %public-key-file)
229 (file-exists? %private-key-file))
230 (leave (_ "key pair exists under '~a'; remove it first~%")
231 (dirname %public-key-file)))
232
233 (format (current-error-port)
234 (_ "Please wait while gathering entropy to generate the key pair;
235this may take time...~%"))
236
237 (let* ((pair (catch 'gcry-error
238 (lambda ()
239 (generate-key parameters))
240 (lambda (key err)
241 (leave (_ "key generation failed: ~a: ~a~%")
242 (error-source err)
243 (error-string err)))))
244 (public (find-sexp-token pair 'public-key))
245 (secret (find-sexp-token pair 'private-key)))
246 ;; Create the following files as #o400.
247 (umask #o266)
248
249 (with-atomic-file-output %public-key-file
250 (lambda (port)
251 (display (canonical-sexp->string public) port)))
252 (with-atomic-file-output %private-key-file
253 (lambda (port)
254 (display (canonical-sexp->string secret) port)))
255
256 ;; Make the public key readable by everyone.
257 (chmod %public-key-file #o444)))
208 258
209(define (guix-archive . args) 259(define (guix-archive . args)
210 (define (parse-options) 260 (define (parse-options)
@@ -220,13 +270,17 @@ resulting archive to the standard output port."
220 ;; Ask for absolute file names so that .drv file names passed from the 270 ;; Ask for absolute file names so that .drv file names passed from the
221 ;; user to 'read-derivation' are absolute when it returns. 271 ;; user to 'read-derivation' are absolute when it returns.
222 (with-fluids ((%file-port-name-canonicalization 'absolute)) 272 (with-fluids ((%file-port-name-canonicalization 'absolute))
223 (let* ((opts (parse-options)) 273 (let ((opts (parse-options)))
224 (store (open-connection))) 274 (cond ((assoc-ref opts 'generate-key)
225 275 =>
226 (cond ((assoc-ref opts 'export) 276 generate-key-pair)
227 (export-from-store store opts))
228 ((assoc-ref opts 'import)
229 (import-paths store (current-input-port)))
230 (else 277 (else
231 (leave 278 (let ((store (open-connection)))
232 (_ "either '--export' or '--import' must be specified")))))))) 279 (cond ((assoc-ref opts 'export)
280 (export-from-store store opts))
281 ((assoc-ref opts 'import)
282 (import-paths store (current-input-port)))
283 (else
284 (leave
285 (_ "either '--export' or '--import' \
286must be specified~%")))))))))))