diff options
| -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 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 | |||
| 942 | comparable in spirit to `tar'. When exporting, the daemon digitally | 942 | comparable in spirit to `tar'. When exporting, the daemon digitally |
| 943 | signs the contents of the archive, and that digital signature is | 943 | signs the contents of the archive, and that digital signature is |
| 944 | appended. When importing, the daemon verifies the signature and rejects | 944 | appended. When importing, the daemon verifies the signature and rejects |
| 945 | the import in case of an invalid signature. | 945 | the import in case of an invalid signature or if the signing key is not |
| 946 | authorized. | ||
| 946 | @c FIXME: Add xref to daemon doc about signatures. | 947 | @c FIXME: Add xref to daemon doc about signatures. |
| 947 | 948 | ||
| 948 | The main options are: | 949 | The main options are: |
| @@ -955,9 +956,11 @@ resulting archive to the standard output. | |||
| 955 | @item --import | 956 | @item --import |
| 956 | Read an archive from the standard input, and import the files listed | 957 | Read an archive from the standard input, and import the files listed |
| 957 | therein into the store. Abort if the archive has an invalid digital | 958 | therein into the store. Abort if the archive has an invalid digital |
| 958 | signature. | 959 | signature, or if it is signed by a public key not among the authorized |
| 960 | keys (see @code{--authorize} below.) | ||
| 959 | 961 | ||
| 960 | @item --generate-key[=@var{parameters}] | 962 | @item --generate-key[=@var{parameters}] |
| 963 | @cindex signing, archives | ||
| 961 | Generate a new key pair for the daemons. This is a prerequisite before | 964 | Generate a new key pair for the daemons. This is a prerequisite before |
| 962 | archives can be exported with @code{--export}. Note that this operation | 965 | archives can be exported with @code{--export}. Note that this operation |
| 963 | usually takes time, because it needs to gather enough entropy to | 966 | 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 | |||
| 970 | @code{genkey} parameters suitable for Libgcrypt (@pxref{General | 973 | @code{genkey} parameters suitable for Libgcrypt (@pxref{General |
| 971 | public-key related Functions, @code{gcry_pk_genkey},, gcrypt, The | 974 | public-key related Functions, @code{gcry_pk_genkey},, gcrypt, The |
| 972 | Libgcrypt Reference Manual}). | 975 | Libgcrypt Reference Manual}). |
| 976 | |||
| 977 | @item --authorize | ||
| 978 | @cindex authorizing, archives | ||
| 979 | Authorize imports signed by the public key passed on standard input. | ||
| 980 | The public key must be in ``s-expression advanced format''---i.e., the | ||
| 981 | same format as the @file{signing-key.pub} file. | ||
| 982 | |||
| 983 | The 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 | ||
| 986 | s-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 | ||
| 975 | To export store files as an archive to the standard output, run: | 991 | To 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 | ||
| 265 | the 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 | ||
| 44 | if guix archive something-that-does-not-exist | 44 | if guix archive something-that-does-not-exist |
| 45 | then false; else true; fi | 45 | then false; else true; fi |
| 46 | |||
| 47 | if echo foo | guix archive --authorize | ||
| 48 | then false; else true; fi | ||
