authenticate: Move actual work to separate procedures.

* guix/scripts/authenticate.scm (read-canonical-sexp): Change to expect
  a port instead of a file name.
  (read-hash-data): Likewise.
  (sign-with-key, validate-signature): New procedures.
  (guix-authenticate): Rewrite in terms of these two procedures.
This commit is contained in:
Ludovic Courtès 2014-03-22 22:38:23 +01:00
parent ed1aff038a
commit 9dbe6e43ea
1 changed files with 48 additions and 38 deletions

View File

@ -34,46 +34,39 @@
;;; ;;;
;;; Code: ;;; Code:
(define (read-canonical-sexp file) (define read-canonical-sexp
"Read a gcrypt sexp from FILE and return it." ;; Read a gcrypt sexp from a port and return it.
(call-with-input-file file (compose string->canonical-sexp get-string-all))
(compose string->canonical-sexp get-string-all)))
(define (read-hash-data file key-type) (define (read-hash-data port key-type)
"Read sha256 hash data from FILE and return it as a gcrypt sexp. KEY-TYPE "Read sha256 hash data from PORT and return it as a gcrypt sexp. KEY-TYPE
is a symbol representing the type of public key algo being used." is a symbol representing the type of public key algo being used."
(let* ((hex (call-with-input-file file get-string-all)) (let* ((hex (get-string-all port))
(bv (base16-string->bytevector (string-trim-both hex)))) (bv (base16-string->bytevector (string-trim-both hex))))
(bytevector->hash-data bv #:key-type key-type))) (bytevector->hash-data bv #:key-type key-type)))
(define (sign-with-key key-file port)
;;; "Sign the hash read from PORT with KEY-FILE, and write an sexp that includes
;;; Entry point with 'openssl'-compatible interface. We support this both the hash and the actual signature."
;;; interface because that's what the daemon expects, and we want to leave it (let* ((secret-key (call-with-input-file key-file read-canonical-sexp))
;;; unmodified currently. (public-key (if (string-suffix? ".sec" key-file)
;;; (call-with-input-file
(string-append (string-drop-right key-file 4)
(define (guix-authenticate . args) ".pub")
(match args read-canonical-sexp)
(("rsautl" "-sign" "-inkey" key "-in" hash-file)
;; Sign the hash in HASH-FILE with KEY, and return an sexp that includes
;; both the hash and the actual signature.
(let* ((secret-key (read-canonical-sexp key))
(public-key (if (string-suffix? ".sec" key)
(read-canonical-sexp
(string-append (string-drop-right key 4) ".pub"))
(leave (leave
(_ "cannot find public key for secret key '~a'~%") (_ "cannot find public key for secret key '~a'~%")
key))) key-file)))
(data (read-hash-data hash-file (key-type public-key))) (data (read-hash-data port (key-type public-key)))
(signature (signature-sexp data secret-key public-key))) (signature (signature-sexp data secret-key public-key)))
(display (canonical-sexp->string signature)) (display (canonical-sexp->string signature))
#t)) #t))
(("rsautl" "-verify" "-inkey" _ "-pubin" "-in" signature-file)
;; Read the signature as produced above, check whether its public key is (define (validate-signature port)
;; authorized, and verify the signature, and print the signed data to "Read the signature from PORT (which is as produced above), check whether
;; stdout upon success. its public key is authorized, verify the signature, and print the signed data
(let* ((signature (read-canonical-sexp signature-file)) to stdout upon success."
(let* ((signature (read-canonical-sexp port))
(subject (signature-subject signature)) (subject (signature-subject signature))
(data (signature-signed-data signature))) (data (signature-signed-data signature)))
(if (and data subject) (if (and data subject)
@ -88,6 +81,23 @@ is a symbol representing the type of public key algo being used."
(canonical-sexp->string subject))) (canonical-sexp->string subject)))
(leave (_ "error: corrupt signature data: ~a~%") (leave (_ "error: corrupt signature data: ~a~%")
(canonical-sexp->string signature))))) (canonical-sexp->string signature)))))
;;;
;;; Entry point with 'openssl'-compatible interface. We support this
;;; interface because that's what the daemon expects, and we want to leave it
;;; unmodified currently.
;;;
(define (guix-authenticate . args)
(match args
(("rsautl" "-sign" "-inkey" key "-in" hash-file)
(call-with-input-file hash-file
(lambda (port)
(sign-with-key key port))))
(("rsautl" "-verify" "-inkey" _ "-pubin" "-in" signature-file)
(call-with-input-file signature-file
(lambda (port)
(validate-signature port))))
(("--help") (("--help")
(display (_ "Usage: guix authenticate OPTION... (display (_ "Usage: guix authenticate OPTION...
Sign or verify the signature on the given file. This tool is meant to Sign or verify the signature on the given file. This tool is meant to