gnu: surgescript: Update to 0.5.4.4.
[jackhill/guix/guix.git] / guix / gnupg.scm
index 5b11aa9..5fae24b 100644 (file)
@@ -1,6 +1,7 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2010, 2011, 2013, 2014, 2016, 2018, 2019 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2013 Nikita Karetnikov <nikita@karetnikov.org>
+;;; Copyright © 2020 Tobias Geerinckx-Rice <me@tobias.gr>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
   ;; unreliable.
   (make-parameter "pool.sks-keyservers.net"))
 
+;; Regexps for status lines.  See file `doc/DETAILS' in GnuPG.
+
+(define sigid-rx
+  (make-regexp
+   "^\\[GNUPG:\\] SIG_ID ([A-Za-z0-9+/]+) ([[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}) ([[:digit:]]+)"))
+(define goodsig-rx
+  (make-regexp "^\\[GNUPG:\\] GOODSIG ([[:xdigit:]]+) (.+)$"))
+(define validsig-rx
+  (make-regexp
+   "^\\[GNUPG:\\] VALIDSIG ([[:xdigit:]]+) ([[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}) ([[:digit:]]+) .*$"))
+(define expkeysig-rx                    ; good signature, but expired key
+  (make-regexp "^\\[GNUPG:\\] EXPKEYSIG ([[:xdigit:]]+) (.*)$"))
+(define revkeysig-rx                    ; good signature, but revoked key
+  (make-regexp "^\\[GNUPG:\\] REVKEYSIG ([[:xdigit:]]+) (.*)$"))
+(define errsig-rx
+  ;; Note: The fingeprint part (the last element of the line) appeared in
+  ;; GnuPG 2.2.7 according to 'doc/DETAILS', and it may be missing.
+  (make-regexp
+   "^\\[GNUPG:\\] ERRSIG ([[:xdigit:]]+) ([^ ]+) ([^ ]+) ([^ ]+) ([[:digit:]]+) ([[:digit:]]+)(.*)"))
+
+
 (define* (gnupg-verify sig file
                        #:optional (keyring (current-keyring)))
   "Verify signature SIG for FILE against the keys in KEYRING.  All the keys in
@@ -71,23 +93,6 @@ revoked.  Return a status s-exp if GnuPG failed."
       (fpr         fpr)))
 
   (define (status-line->sexp line)
-    ;; See file `doc/DETAILS' in GnuPG.
-    (define sigid-rx
-      (make-regexp
-       "^\\[GNUPG:\\] SIG_ID ([A-Za-z0-9+/]+) ([[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}) ([[:digit:]]+)"))
-    (define goodsig-rx
-      (make-regexp "^\\[GNUPG:\\] GOODSIG ([[:xdigit:]]+) (.+)$"))
-    (define validsig-rx
-      (make-regexp
-       "^\\[GNUPG:\\] VALIDSIG ([[:xdigit:]]+) ([[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}) ([[:digit:]]+) .*$"))
-    (define expkeysig-rx                    ; good signature, but expired key
-      (make-regexp "^\\[GNUPG:\\] EXPKEYSIG ([[:xdigit:]]+) (.*)$"))
-    (define errsig-rx
-      ;; Note: The fingeprint part (the last element of the line) appeared in
-      ;; GnuPG 2.2.7 according to 'doc/DETAILS', and it may be missing.
-      (make-regexp
-       "^\\[GNUPG:\\] ERRSIG ([[:xdigit:]]+) ([^ ]+) ([^ ]+) ([^ ]+) ([[:digit:]]+) ([[:digit:]]+)(.*)"))
-
     (cond ((regexp-exec sigid-rx line)
            =>
            (lambda (match)
@@ -112,6 +117,11 @@ revoked.  Return a status s-exp if GnuPG failed."
            (lambda (match)
              `(expired-key-signature ,(match:substring match 1) ; fingerprint
                                      ,(match:substring match 2)))) ; user name
+          ((regexp-exec revkeysig-rx line)
+           =>
+           (lambda (match)
+             `(revoked-key-signature ,(match:substring match 1) ; fingerprint
+                                     ,(match:substring match 2)))) ; user name
           ((regexp-exec errsig-rx line)
            =>
            (lambda (match)
@@ -155,7 +165,8 @@ a fingerprint/user pair; return #f otherwise."
   (match (assq 'valid-signature status)
     (('valid-signature fingerprint date timestamp)
      (match (or (assq 'good-signature status)
-                (assq 'expired-key-signature status))
+                (assq 'expired-key-signature status)
+                (assq 'revoked-key-signature status))
        ((_ key-id user) (cons fingerprint user))
        (_ #f)))
     (_
@@ -173,13 +184,15 @@ missing key or its key id if the fingerprint is unavailable."
 
 (define* (gnupg-receive-keys fingerprint/key-id server
                              #:optional (keyring (current-keyring)))
+  "Download FINGERPRINT/KEY-ID from SERVER, a key server, and add it to
+KEYRING."
   (unless (file-exists? keyring)
     (mkdir-p (dirname keyring))
     (call-with-output-file keyring (const #t)))   ;create an empty keybox
 
-  (system* (%gpg-command) "--keyserver" server
-           "--no-default-keyring" "--keyring" keyring
-           "--recv-keys" fingerprint/key-id))
+  (zero? (system* (%gpg-command) "--keyserver" server
+                  "--no-default-keyring" "--keyring" keyring
+                  "--recv-keys" fingerprint/key-id)))
 
 (define* (gnupg-verify* sig file
                         #:key
@@ -187,36 +200,48 @@ missing key or its key id if the fingerprint is unavailable."
                         (server (%openpgp-key-server))
                         (keyring (current-keyring)))
   "Like `gnupg-verify', but try downloading the public key if it's missing.
-Return #t if the signature was good, #f otherwise.  KEY-DOWNLOAD specifies a
-download policy for missing OpenPGP keys; allowed values: 'always', 'never',
-and 'interactive' (default).  Return a fingerprint/user name pair on success
-and #f otherwise."
+Return two values: 'valid-signature and a fingerprint/name pair upon success,
+'missing-key and a fingerprint if the key could not be found, and
+'invalid-signature with a fingerprint if the signature is invalid.
+
+KEY-DOWNLOAD specifies a download policy for missing OpenPGP keys; allowed
+values: 'always', 'never', and 'interactive' (default).  Return a
+fingerprint/user name pair on success and #f otherwise."
   (let ((status (gnupg-verify sig file)))
-    (or (gnupg-status-good-signature? status)
-        (let ((missing (gnupg-status-missing-key? status)))
-          (define (download-and-try-again)
-            ;; Download the missing key and try again.
-            (begin
-              (gnupg-receive-keys missing server keyring)
-              (gnupg-status-good-signature? (gnupg-verify sig file
-                                                          keyring))))
-
-          (define (receive?)
-            (let ((answer
-                   (begin
-                     (format #t (G_ "Would you like to add this key \
+    (match (gnupg-status-good-signature? status)
+      ((fingerprint . user)
+       (values 'valid-signature (cons fingerprint user)))
+      (#f
+       (let ((missing (gnupg-status-missing-key? status)))
+         (define (download-and-try-again)
+           ;; Download the missing key and try again.
+           (if (gnupg-receive-keys missing server keyring)
+               (match (gnupg-status-good-signature?
+                       (gnupg-verify sig file keyring))
+                 (#f
+                  (values 'invalid-signature missing))
+                 ((fingerprint . user)
+                  (values 'valid-signature
+                          (cons fingerprint user))))
+               (values 'missing-key missing)))
+
+         (define (receive?)
+           (let ((answer
+                  (begin
+                    (format #t (G_ "Would you like to add this key \
 to keyring '~a'?~%")
-                             keyring)
-                     (read-line))))
-              (string-match (locale-yes-regexp) answer)))
-
-          (and missing
-               (case key-download
-                 ((never) #f)
-                 ((always)
-                  (download-and-try-again))
-                 (else
-                  (and (receive?)
-                       (download-and-try-again)))))))))
+                            keyring)
+                    (read-line))))
+             (string-match (locale-yes-regexp) answer)))
+
+         (case key-download
+           ((never)
+            (values 'missing-key missing))
+           ((always)
+            (download-and-try-again))
+           (else
+            (if (receive?)
+                (download-and-try-again)
+                (values 'missing-key missing)))))))))
 
 ;;; gnupg.scm ends here