Subject: bug#57599: closed (Re: bug#57599: [PATCH] openpgp: Add support for ECDSA with NIST curves.)

From: [email-masked] (GNU bug Tracking System)
Date: Sat, 24 Sep 2022 09:54:02 +0000

Your bug report

#57599: [PATCH] openpgp: Add support for ECDSA with NIST curves.

which was filed against the guix-patches package, has been closed.

The explanation is attached below, along with your original report.
If you require more details, please reply to [email-masked].

-- 
57599: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=57599
GNU Bug Tracking System
Contact [email-masked] with problems

Subject: Re: bug#57599: [PATCH] openpgp: Add support for ECDSA with NIST curves.
From: Ludovic Courtès <[email-masked]>
To: [email-masked]
Cc: [email-masked], Andreas Enge <[email-masked]>, Maxime Devos <[email-masked]>, Zhu Zihao <[email-masked]>
Date: Sat, 24 Sep 2022 11:53:32 +0200
List-Id: <debbugs-submit.debbugs.gnu.org>

Hi!

All things considered, I prefer to drop this patch.  In the unlikely
event that we’ll get more requests to support these curves, we can
always revisit the issue.

What we should do, though, is improve error reporting in case an
unsupported curve or algorithm is encountered.

Thanks,
Ludo’.

Subject: [PATCH] openpgp: Add support for ECDSA with NIST curves.
From: Ludovic Courtès <[email-masked]>
To: [email-masked]
Cc: Ludovic Courtès <[email-masked]>
Date: Mon, 5 Sep 2022 18:09:29 +0200
List-Id: <debbugs-submit.debbugs.gnu.org>

Fixes <https://issues.guix.gnu.org/57576>.
Reported by Zhu Zihao <[email-masked]>.

* guix/openpgp.scm (verify-openpgp-signature): Add case for ecdsa.
(get-signature): Likewise for PUBLIC-KEY-ECDSA.
(get-public-key): Likewise.
* tests/keys/secp384.pub, tests/keys/secp384.sec,
tests/keys/secp521.pub, tests/keys/secp521.sec: New files.
* Makefile.am (EXTRA_DIST): Add them.
* tests/openpgp.scm (%secp384-key-id, %secp384-key-fingerprint)
(%hello-signature/secp384/sha384)
(%secp521-key-id, %secp521-key-fingerprint)
(%hello-signature/secp521/sha521): New variables.
* tests/openpgp.scm ("get-openpgp-detached-signature/ascii")
("verify-openpgp-signature, good signatures")
("verify-openpgp-signature, bad signature"): Check with
the secp384 and secp521 curves.
---
 Makefile.am            |  4 +++
 guix/openpgp.scm       | 41 +++++++++++++++++++++-----
 tests/keys/secp384.pub | 11 +++++++
 tests/keys/secp384.sec | 12 ++++++++
 tests/keys/secp521.pub | 13 +++++++++
 tests/keys/secp521.sec | 14 +++++++++
 tests/openpgp.scm      | 66 +++++++++++++++++++++++++++++++++++-------
 7 files changed, 143 insertions(+), 18 deletions(-)
 create mode 100644 tests/keys/secp384.pub
 create mode 100644 tests/keys/secp384.sec
 create mode 100644 tests/keys/secp521.pub
 create mode 100644 tests/keys/secp521.sec

diff --git a/Makefile.am b/Makefile.am
index a0c4e941c1..71c3bd4a98 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -702,6 +702,10 @@ EXTRA_DIST +=						\
   tests/keys/ed25519-2.sec				\
   tests/keys/ed25519-3.pub				\
   tests/keys/ed25519-3.sec				\
+  tests/keys/secp384.pub				\
+  tests/keys/secp384.sec				\
+  tests/keys/secp521.pub				\
+  tests/keys/secp521.sec				\
   build-aux/config.rpath				\
   bootstrap						\
   doc/build.scm						\
diff --git a/guix/openpgp.scm b/guix/openpgp.scm
index 9de7feb644..b999c30474 100644
--- a/guix/openpgp.scm
+++ b/guix/openpgp.scm
@@ -1,6 +1,6 @@
 ;; -*- mode: scheme; coding: utf-8 -*-
 ;; Copyright © 2010, 2012 Göran Weinholt <[email-masked]>
-;; Copyright © 2020 Ludovic Courtès <[email-masked]>
+;; Copyright © 2020, 2022 Ludovic Courtès <[email-masked]>
 
 ;; Permission is hereby granted, free of charge, to any person obtaining a
 ;; copy of this software and associated documentation files (the "Software"),
@@ -290,7 +290,7 @@ (define PUBLIC-KEY-RSA-SIGN-ONLY 3)
 (define PUBLIC-KEY-ELGAMAL-ENCRYPT-ONLY 16)
 (define PUBLIC-KEY-DSA 17)
 (define PUBLIC-KEY-ECDH 18)                       ;RFC-6637
-(define PUBLIC-KEY-ECDSA 19)                      ;RFC-6639
+(define PUBLIC-KEY-ECDSA 19)                      ;RFC-6637
 (define PUBLIC-KEY-ELGAMAL 20)                    ;encrypt + sign (legacy)
 (define PUBLIC-KEY-EDDSA 22)                      ;"not yet assigned" says GPG
 
@@ -298,6 +298,7 @@ (define (public-key-algorithm id)
   (cond ((= id PUBLIC-KEY-RSA) 'rsa)
         ((= id PUBLIC-KEY-DSA) 'dsa)
         ((= id PUBLIC-KEY-ELGAMAL-ENCRYPT-ONLY) 'elgamal)
+        ((= id PUBLIC-KEY-ECDSA) 'ecdsa)
         ((= id PUBLIC-KEY-EDDSA) 'eddsa)
         (else id)))
 
@@ -564,10 +565,16 @@ (define (check key sig)
               ;; See "(gcrypt) Cryptographic Functions".
               (sexp->canonical-sexp
                (if (eq? key-type 'ecc)
-                   `(data
-                     (flags eddsa)
-                     (hash-algo sha512)
-                     (value ,hash))
+                   (match (openpgp-signature-public-key-algorithm sig)
+                     ('eddsa
+                      `(data
+                        (flags eddsa)
+                        (hash-algo sha512)
+                        (value ,hash)))
+                     ('ecdsa
+                      `(data
+                        (hash-algo ,(openpgp-signature-hash-algorithm sig))
+                        (value ,hash))))
                    `(data
                      (flags ,(match key-type
                                ('rsa 'pkcs1)
@@ -615,7 +622,8 @@ (define (get-sig p pkalg)
              (string->canonical-sexp
               (format #f "(sig-val (dsa (r #~a#) (s #~a#)))"
                       (->hex r) (->hex s)))))
-          ((= pkalg PUBLIC-KEY-EDDSA)
+          ((or (= pkalg PUBLIC-KEY-EDDSA)
+               (= pkalg PUBLIC-KEY-ECDSA))
            (print "EdDSA signature")
            (let ((r (get-mpi/bytevector p))
                  (s (get-mpi/bytevector p)))
@@ -630,7 +638,8 @@ (define (bytevector->hex bv)
                      str)))
 
              (string->canonical-sexp
-              (format #f "(sig-val (eddsa (r #~a#) (s #~a#)))"
+              (format #f "(sig-val (~a (r #~a#) (s #~a#)))"
+                      (public-key-algorithm pkalg)
                       (bytevector->hex r) (bytevector->hex s)))))
           (else
            (list 'unsupported-algorithm
@@ -886,6 +895,22 @@ (define curve
                       curve
                       (if (eq? curve 'Curve25519) 'djb-tweak 'eddsa)
                       (->hex q)))))
+          ((= alg PUBLIC-KEY-ECDSA)
+           (print "Public ECDSA key")
+           (let* ((len     (get-u8 p))
+                  (oid     (bytevector->uint (get-bytevector-n p len)))
+                  (q (get-mpi p)))
+             (define curve
+               ;; RFC 6637, Section 11.
+               (match oid
+                 (#x2a8648ce3d030107   "NIST P-256")
+                 (#x2b81040022         "NIST P-384")
+                 (#x2b81040023         "NIST P-521")))
+
+             (string->canonical-sexp
+              (format #f "(public-key (ecc (curve \"~a\")(q #~a#)))"
+                      curve
+                      (->hex q)))))
           (else
            (list 'unsupported-algorithm           ;FIXME: throw
                  (public-key-algorithm alg)
diff --git a/tests/keys/secp384.pub b/tests/keys/secp384.pub
new file mode 100644
index 0000000000..b90cf504e2
--- /dev/null
+++ b/tests/keys/secp384.pub
@@ -0,0 +1,11 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mG8EYxYF9RMFK4EEACIDAwTHYxcyBiiPz4ZZIkmXnVu0Yv9DHGrnbdCR6U/RT1S4
+wszaHdsSEHlPwmy3WGgTubBDOuJODf5kV/HLL7QEPsOTkIsObK+prEJO3CGpRVim
+a7nfVk2AH6D/GMkNacSXdwy0FTxleGFtcGxlQGV4YW1wbGUuY29tPoiwBBMTCQA4
+AhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAFiEEzLZ9Sx8EBzgp+PzwLydGMf8+
+bFsFAmMWB+sACgkQLydGMf8+bFuD3gF/SMEDQP3Bvu0yb8KxE6j8lhOiKT186wwG
+4hBsifRdEF+UHWEa7sx74tyc4R1B01FUAYC/4QqNup4EnPzQfSE3WyVvu+ja+xui
+3vppYCpUjkHzkATsLzsN98/nkZ3q3YA8/lo=
+=vIaC
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/tests/keys/secp384.sec b/tests/keys/secp384.sec
new file mode 100644
index 0000000000..ae296dd9a1
--- /dev/null
+++ b/tests/keys/secp384.sec
@@ -0,0 +1,12 @@
+-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+lKQEYxYF9RMFK4EEACIDAwTHYxcyBiiPz4ZZIkmXnVu0Yv9DHGrnbdCR6U/RT1S4
+wszaHdsSEHlPwmy3WGgTubBDOuJODf5kV/HLL7QEPsOTkIsObK+prEJO3CGpRVim
+a7nfVk2AH6D/GMkNacSXdwwAAYC9iXZ9j+RWFB4rU103SCv6j68rS5Lmc7tHve9l
+B5nri/AR+OEJ61q+w6w0XO5GBBUYLrQVPGV4YW1wbGVAZXhhbXBsZS5jb20+iLAE
+ExMJADgCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AWIQTMtn1LHwQHOCn4/PAv
+J0Yx/z5sWwUCYxYH6wAKCRAvJ0Yx/z5sW4PeAX9IwQNA/cG+7TJvwrETqPyWE6Ip
+PXzrDAbiEGyJ9F0QX5QdYRruzHvi3JzhHUHTUVQBgL/hCo26ngSc/NB9ITdbJW+7
+6Nr7G6Le+mlgKlSOQfOQBOwvOw33z+eRnerdgDz+Wg==
+=B1Nl
+-----END PGP PRIVATE KEY BLOCK-----
diff --git a/tests/keys/secp521.pub b/tests/keys/secp521.pub
new file mode 100644
index 0000000000..077e8e7df2
--- /dev/null
+++ b/tests/keys/secp521.pub
@@ -0,0 +1,13 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+=Nru3
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/tests/keys/secp521.sec b/tests/keys/secp521.sec
new file mode 100644
index 0000000000..663dbeaa3c
--- /dev/null
+++ b/tests/keys/secp521.sec
@@ -0,0 +1,14 @@
+-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+=/mn1
+-----END PGP PRIVATE KEY BLOCK-----
diff --git a/tests/openpgp.scm b/tests/openpgp.scm
index 1f20466772..68439f7485 100644
--- a/tests/openpgp.scm
+++ b/tests/openpgp.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2020 Ludovic Courtès <[email-masked]>
+;;; Copyright © 2020, 2022 Ludovic Courtès <[email-masked]>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -63,7 +63,7 @@ (define %civodul-key-id #x090B11993D9AEBB5)       ;civodul.pub
 
 #|
 Test keys in ./tests/keys.  They were generated in a container along these lines:
-  guix environment -CP --ad-hoc gnupg pinentry coreutils
+  guix shell -CP-hoc gnupg pinentry coreutils
 then, within the container:
   mkdir ~/.gnupg && chmod -R og-rwx ~/.gnupg
   gpg --batch --passphrase '' --quick-gen-key '<[email-masked]>' ed25519
@@ -75,6 +75,8 @@ (define %civodul-key-id #x090B11993D9AEBB5)       ;civodul.pub
 (define %rsa-key-id      #xAE25DA2A70DEED59)      ;rsa.pub
 (define %dsa-key-id      #x587918047BE8BD2C)      ;dsa.pub
 (define %ed25519-key-id  #x771F49CBFAAE072D)      ;ed25519.pub
+(define %secp384-key-id  #x2F274631FF3E6C5B)      ;secp384.pub
+(define %secp521-key-id  #xE84B13A0B4E7AF1B)      ;secp521.pub
 
 (define %rsa-key-fingerprint
   (base16-string->bytevector
@@ -85,6 +87,12 @@ (define %dsa-key-fingerprint
 (define %ed25519-key-fingerprint
   (base16-string->bytevector
    (string-downcase "44D31E21AF7138F9B632280A771F49CBFAAE072D")))
+(define %secp384-key-fingerprint
+  (base16-string->bytevector
+   (string-downcase "CCB67D4B1F04073829F8FCF02F274631FF3E6C5B")))
+(define %secp521-key-fingerprint
+  (base16-string->bytevector
+   (string-downcase "3BAF7E984069B671F3C31169E84B13A0B4E7AF1B")))
 
 
 ;;; The following are detached signatures created commands like:
@@ -148,6 +156,28 @@ (define %hello-signature/ed25519/sha1             ;digest-algo: sha1
 =AE4G
 -----END PGP SIGNATURE-----")
 
+(define %hello-signature/secp384/sha384           ;digest-algo: sha384
+  "\
+-----BEGIN PGP SIGNATURE-----
+
+iJUEABMJAB0WIQTMtn1LHwQHOCn4/PAvJ0Yx/z5sWwUCYxYIKAAKCRAvJ0Yx/z5s
+WxD2AX0QMeTHLJvJxRKTBP8O9kGMY9Nz0kzRBO0OJG2gYyxu9sZ+NAEQF01jAOXl
+ApL2zVkBgLUyyleJtR24LKxK73waLJb51TA29NXJJZ2fiRZ50u/lNfrFR3PYnK7/
+gvSkL3Ldzw==
+=+7h3
+-----END PGP SIGNATURE-----")
+
+(define %hello-signature/secp521/sha512
+  "\
+-----BEGIN PGP SIGNATURE-----
+
+iLcEABMKAB0WIQQ7r36YQGm2cfPDEWnoSxOgtOevGwUCYxYb+wAKCRDoSxOgtOev
+G+ByAgdwIBTnCtzo+lFuahhMMScXZZeTH055IOhTsXmptZaE3MaazTsUw3en8C9i
+EWiy/GDQKaJEZMP3dwN1+3tNTl/NUAIIiV/BFly9Ha/cYJG+p3LG24JoHVfJx04q
+LfSXejfMIvu33h8wjMA2tRQSlqdDylMWKThJgp6GH6svp+Zr4z+Smnw=
+=1zW0
+-----END PGP SIGNATURE-----")
+
 
 (test-begin "openpgp")
 
@@ -193,7 +223,9 @@ (define %hello-signature/ed25519/sha1             ;digest-algo: sha1
         `(,%rsa-key-id ,%rsa-key-fingerprint rsa sha256)
         `(,%ed25519-key-id ,%ed25519-key-fingerprint eddsa sha256)
         `(,%ed25519-key-id ,%ed25519-key-fingerprint eddsa sha512)
-        `(,%ed25519-key-id ,%ed25519-key-fingerprint eddsa sha1))
+        `(,%ed25519-key-id ,%ed25519-key-fingerprint eddsa sha1)
+        `(,%secp384-key-id ,%secp384-key-fingerprint ecdsa sha384)
+        `(,%secp521-key-id ,%secp521-key-fingerprint ecdsa sha512))
   (map (lambda (str)
          (let ((signature (get-openpgp-detached-signature/ascii
                            (open-input-string str))))
@@ -205,7 +237,9 @@ (define %hello-signature/ed25519/sha1             ;digest-algo: sha1
              %hello-signature/rsa
              %hello-signature/ed25519/sha256
              %hello-signature/ed25519/sha512
-             %hello-signature/ed25519/sha1)))
+             %hello-signature/ed25519/sha1
+             %hello-signature/secp384/sha384
+             %hello-signature/secp521/sha512)))
 
 (test-equal "verify-openpgp-signature, missing key"
   `(missing-key ,%rsa-key-fingerprint)
@@ -221,7 +255,9 @@ (define %hello-signature/ed25519/sha1             ;digest-algo: sha1
     (good-signature ,%dsa-key-id)
     (good-signature ,%ed25519-key-id)
     (good-signature ,%ed25519-key-id)
-    (good-signature ,%ed25519-key-id))
+    (good-signature ,%ed25519-key-id)
+    (good-signature ,%secp384-key-id)
+    (good-signature ,%secp521-key-id))
   (map (lambda (key signature)
          (let* ((key       (search-path %load-path key))
                 (keyring   (get-openpgp-keyring
@@ -235,18 +271,24 @@ (define %hello-signature/ed25519/sha1             ;digest-algo: sha1
        (list "tests/keys/rsa.pub" "tests/keys/dsa.pub"
              "tests/keys/ed25519.pub"
              "tests/keys/ed25519.pub"
-             "tests/keys/ed25519.pub")
+             "tests/keys/ed25519.pub"
+             "tests/keys/secp384.pub"
+             "tests/keys/secp521.pub")
        (list %hello-signature/rsa %hello-signature/dsa
              %hello-signature/ed25519/sha256
              %hello-signature/ed25519/sha512
-             %hello-signature/ed25519/sha1)))
+             %hello-signature/ed25519/sha1
+             %hello-signature/secp384/sha384
+             %hello-signature/secp521/sha512)))
 
 (test-equal "verify-openpgp-signature, bad signature"
   `((bad-signature ,%rsa-key-id)
     (bad-signature ,%dsa-key-id)
     (bad-signature ,%ed25519-key-id)
     (bad-signature ,%ed25519-key-id)
-    (bad-signature ,%ed25519-key-id))
+    (bad-signature ,%ed25519-key-id)
+    (bad-signature ,%secp384-key-id)
+    (bad-signature ,%secp521-key-id))
   (let ((keyring (fold (lambda (key keyring)
                          (let ((key (search-path %load-path key)))
                            (get-openpgp-keyring
@@ -256,7 +298,9 @@ (define %hello-signature/ed25519/sha1             ;digest-algo: sha1
                        %empty-keyring
                        '("tests/keys/rsa.pub" "tests/keys/dsa.pub"
                          "tests/keys/ed25519.pub" "tests/keys/ed25519.pub"
-                         "tests/keys/ed25519.pub"))))
+                         "tests/keys/ed25519.pub"
+                         "tests/keys/secp384.pub"
+                         "tests/keys/secp521.pub"))))
     (map (lambda (signature)
            (let ((signature (string->openpgp-packet signature)))
              (let-values (((status key)
@@ -266,6 +310,8 @@ (define %hello-signature/ed25519/sha1             ;digest-algo: sha1
          (list %hello-signature/rsa %hello-signature/dsa
                %hello-signature/ed25519/sha256
                %hello-signature/ed25519/sha512
-               %hello-signature/ed25519/sha1))))
+               %hello-signature/ed25519/sha1
+               %hello-signature/secp384/sha384
+               %hello-signature/secp521/sha512))))
 
 (test-end "openpgp")

base-commit: aae98c297214f87eb45302863adb021078c41a6f
-- 
2.37.2