summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--guix/pk-crypto.scm27
-rw-r--r--guix/scripts/authenticate.scm9
-rw-r--r--tests/pk-crypto.scm40
3 files changed, 65 insertions, 11 deletions
diff --git a/guix/pk-crypto.scm b/guix/pk-crypto.scm
index 50f709418c..b9ab02861c 100644
--- a/guix/pk-crypto.scm
+++ b/guix/pk-crypto.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2013 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2013, 2014 Ludovic Courtès <ludo@gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -39,6 +39,7 @@
             canonical-sexp-list?
             bytevector->hash-data
             hash-data->bytevector
+            key-type
             sign
             verify
             generate-key
@@ -232,15 +233,31 @@ Return #f if that element does not exist, or if it's a list."
   "Return an s-expression representing NUMBER."
   (string->canonical-sexp (string-append "#" (number->string number 16) "#")))
 
-(define* (bytevector->hash-data bv #:optional (hash-algo "sha256"))
+(define* (bytevector->hash-data bv
+                                #:optional
+                                (hash-algo "sha256")
+                                #:key (key-type 'ecc))
   "Given BV, a bytevector containing a hash, return an s-expression suitable
-for use as the data for 'sign'."
+for use as the data for 'sign'.  KEY-TYPE must be a symbol: 'dsa, 'ecc, or
+'rsa."
   (string->canonical-sexp
-   (format #f "(data (flags pkcs1) (hash \"~a\" #~a#))"
+   (format #f "(data (flags ~a) (hash \"~a\" #~a#))"
+           (case key-type
+             ((ecc dsa) "rfc6979")
+             ((rsa)     "pkcs1")
+             (else (error "unknown key type" key-type)))
            hash-algo
            (bytevector->base16-string bv))))
 
-(define (hash-data->bytevector data)
+(define (key-type sexp)
+  "Return a symbol denoting the type of key representing by SEXP--e.g., 'rsa',
+'ecc'--or #f if SEXP does not denote a valid key."
+  (case (canonical-sexp-nth-data sexp 0)
+    ((public-key private-key)
+     (canonical-sexp-nth-data (canonical-sexp-nth sexp 1) 0))
+    (else #f)))
+
+(define* (hash-data->bytevector data)
   "Return two values: the hash value (a bytevector), and the hash algorithm (a
 string) extracted from DATA, an sexp as returned by 'bytevector->hash-data'.
 Return #f if DATA does not conform."
diff --git a/guix/scripts/authenticate.scm b/guix/scripts/authenticate.scm
index 27580dedff..927dbe8afc 100644
--- a/guix/scripts/authenticate.scm
+++ b/guix/scripts/authenticate.scm
@@ -39,11 +39,12 @@
   (call-with-input-file file
     (compose string->canonical-sexp get-string-all)))
 
-(define (read-hash-data file)
-  "Read sha256 hash data from FILE and return it as a gcrypt sexp."
+(define (read-hash-data file key-type)
+  "Read sha256 hash data from FILE and return it as a gcrypt sexp.  KEY-TYPE
+is a symbol representing the type of public key algo being used."
   (let* ((hex (call-with-input-file file get-string-all))
          (bv  (base16-string->bytevector (string-trim-both hex))))
-    (bytevector->hash-data bv)))
+    (bytevector->hash-data bv #:key-type key-type)))
 
 
 ;;;
@@ -64,7 +65,7 @@
                             (leave
                              (_ "cannot find public key for secret key '~a'~%")
                              key)))
-            (data       (read-hash-data hash-file))
+            (data       (read-hash-data hash-file (key-type public-key)))
             (signature  (signature-sexp data secret-key public-key)))
        (display (canonical-sexp->string signature))
        #t))
diff --git a/tests/pk-crypto.scm b/tests/pk-crypto.scm
index 6774dd4157..4d498020f5 100644
--- a/tests/pk-crypto.scm
+++ b/tests/pk-crypto.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2013 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2013, 2014 Ludovic Courtès <ludo@gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -31,7 +31,7 @@
 ;; Test the (guix pk-crypto) module.
 
 (define %key-pair
-  ;; Key pair that was generated with:
+  ;; RSA key pair that was generated with:
   ;;   (generate-key (string->canonical-sexp "(genkey (rsa (nbits 4:1024)))"))
   ;; which takes a bit of time.
   "(key-data
@@ -48,6 +48,20 @@
       (q #00E9AD22F158060BC9AE3601DA623AFC60FFF3058795802CA92371C00097335CF9A23D7782DE353C9DBA93D7BB99E6A24A411107605E722481C5C191F80D7EB77F#)
       (u #59B45B95AE01A7A7370FAFDB08FE73A4793CE37F228961B09B1B1E7DDAD9F8D3E28F5C5E8B4B067E6B8E0BBF3F690B42991A79E46108DDCDA2514323A66964DE#))))")
 
+(define %ecc-key-pair
+  ;; Ed25519 key pair generated with:
+  ;;   (generate-key (string->canonical-sexp "(genkey (ecdsa (curve Ed25519) (flags rfc6979 transient)))"))
+  "(key-data
+      (public-key
+        (ecc
+          (curve Ed25519)
+          (q #94869C1B9E69DB8DD910B7F7F4D6E56A63A964A59AE8F90F6703ACDDF6F50C81#)))
+      (private-key
+        (ecc
+          (curve Ed25519)
+          (q #94869C1B9E69DB8DD910B7F7F4D6E56A63A964A59AE8F90F6703ACDDF6F50C81#)
+          (d #6EFB32D0B4EC6B3237B523539F1979379B82726AAA605EB2FBA6775B2B777B78#))))")
+
 (test-begin "pk-crypto")
 
 (let ((sexps '("(foo bar)"
@@ -148,11 +162,33 @@
            (and (string=? algo "sha256")
                 (bytevector=? value bv))))))
 
+(test-equal "key-type"
+  '(rsa ecc)
+  (map (compose key-type
+                (cut find-sexp-token <> 'public-key)
+                string->canonical-sexp)
+       (list %key-pair %ecc-key-pair)))
+
 (test-assert "sign + verify"
   (let* ((pair   (string->canonical-sexp %key-pair))
          (secret (find-sexp-token pair 'private-key))
          (public (find-sexp-token pair 'public-key))
          (data   (bytevector->hash-data
+                  (sha256 (string->utf8 "Hello, world."))
+                  #:key-type (key-type public)))
+         (sig    (sign data secret)))
+    (and (verify sig data public)
+         (not (verify sig
+                      (bytevector->hash-data
+                       (sha256 (string->utf8 "Hi!"))
+                       #:key-type (key-type public))
+                      public)))))
+
+(test-assert "sign + verify, Ed25519"
+  (let* ((pair   (string->canonical-sexp %ecc-key-pair))
+         (secret (find-sexp-token pair 'private-key))
+         (public (find-sexp-token pair 'public-key))
+         (data   (bytevector->hash-data
                   (sha256 (string->utf8 "Hello, world."))))
          (sig    (sign data secret)))
     (and (verify sig data public)