launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #30744
[Merge] ~cjwatson/launchpad:gpg-eddsa into launchpad:master
Colin Watson has proposed merging ~cjwatson/launchpad:gpg-eddsa into launchpad:master.
Commit message:
Add support for EdDSA GnuPG keys
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #1827369 in Launchpad itself: "Launchpad cannot handle ECC or Ed25519 OpenPGP keys"
https://bugs.launchpad.net/launchpad/+bug/1827369
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/456006
These should work now that we're running on focal.
I'm afraid unit testing for this slightly defeated me in the time available, but I've at least manually tested that `gpghandler.retrieveKey` now works for an EdDSA key, which I think demonstrated the underlying problems on xenial.
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:gpg-eddsa into launchpad:master.
diff --git a/lib/lp/registry/model/gpgkey.py b/lib/lp/registry/model/gpgkey.py
index eb34738..f499faf 100644
--- a/lib/lp/registry/model/gpgkey.py
+++ b/lib/lp/registry/model/gpgkey.py
@@ -11,7 +11,11 @@ from lp.registry.interfaces.gpg import IGPGKey, IGPGKeySet
from lp.services.database.enumcol import DBEnum
from lp.services.database.interfaces import IStore
from lp.services.database.stormbase import StormBase
-from lp.services.gpg.interfaces import GPGKeyAlgorithm, IGPGHandler
+from lp.services.gpg.interfaces import (
+ GPGKeyAlgorithm,
+ IGPGHandler,
+ gpg_algorithm_letter,
+)
from lp.services.verification.model.logintoken import LoginToken
@@ -67,7 +71,7 @@ class GPGKey(StormBase):
def displayname(self):
return "%s%s/%s" % (
self.keysize,
- self.algorithm.title,
+ gpg_algorithm_letter(self.algorithm),
self.fingerprint,
)
diff --git a/lib/lp/registry/templates/person-editpgpkeys.pt b/lib/lp/registry/templates/person-editpgpkeys.pt
index f6dd57b..169c5f0 100644
--- a/lib/lp/registry/templates/person-editpgpkeys.pt
+++ b/lib/lp/registry/templates/person-editpgpkeys.pt
@@ -163,12 +163,6 @@
fingerprint</a>)
</p>
- <p>
- At present, only RSA, DSA, and some ECC keys are supported; see
- <a href="https://bugs.launchpad.net/launchpad/+bug/1827369">bug
- 1827369</a> for details on the state of support for other key types.
- </p>
-
<table class="form" id="launchpad-form-widgets">
<tbody>
<tr>
diff --git a/lib/lp/services/gpg/handler.py b/lib/lp/services/gpg/handler.py
index bb354e0..b994f7d 100644
--- a/lib/lp/services/gpg/handler.py
+++ b/lib/lp/services/gpg/handler.py
@@ -48,6 +48,7 @@ from lp.services.gpg.interfaces import (
get_gpg_home_directory,
get_gpg_path,
get_gpgme_context,
+ gpg_algorithm_letter,
valid_fingerprint,
)
from lp.services.signing.enums import SigningKeyType
@@ -672,7 +673,7 @@ class PymeKey:
def displayname(self):
return "%s%s/%s" % (
self.keysize,
- self.algorithm.title,
+ gpg_algorithm_letter(self.algorithm),
self.fingerprint,
)
diff --git a/lib/lp/services/gpg/interfaces.py b/lib/lp/services/gpg/interfaces.py
index 6dec53a..1aecb5d 100644
--- a/lib/lp/services/gpg/interfaces.py
+++ b/lib/lp/services/gpg/interfaces.py
@@ -15,6 +15,7 @@ __all__ = [
"GPGKeyTemporarilyNotFoundError",
"GPGUploadFailure",
"GPGVerificationError",
+ "gpg_algorithm_letter",
"IGPGHandler",
"IPymeKey",
"IPymeSignature",
@@ -119,75 +120,45 @@ def get_gpgme_context():
return context
-# XXX: cprov 2004-10-04:
-# (gpg+dbschema) the data structure should be rearranged to support 4 field
-# needed: keynumber(1,16,17,20), keyalias(R,g,D,G), title and description
class GPGKeyAlgorithm(DBEnumeratedType):
"""
- GPG Compliant Key Algorithms Types:
-
- 1 : "R", # RSA
- 16 : "g", # ElGamal
- 17 : "D", # DSA
- 20 : "G", # ElGamal, compromised
- 301: "E", # ECDSA
- 302: "e", # ECDH
-
- See `pubkey_letter` in GnuPG for the single-letter codes used here.
-
- FIXME
- Rewrite it according to the experimental API returning also a name
- attribute tested on 'algorithmname' attribute
+ GPG Public Key Algorithm
+ The numbers must match those in `gpgme_hash_algo_t`
+ (https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gpgme.git;a=blob;f=src/gpgme.h.in).
"""
- R = DBItem(
- 1,
- """
- R
-
- RSA""",
- )
-
- LITTLE_G = DBItem(
- 16,
- """
- g
+ R = DBItem(1, "RSA")
+ LITTLE_G = DBItem(16, "ElGamal")
+ D = DBItem(17, "DSA")
+ G = DBItem(20, "ElGamal, compromised")
+ ECDSA = DBItem(301, "ECDSA")
+ ECDH = DBItem(302, "ECDH")
+ EDDSA = DBItem(303, "EDDSA")
- ElGamal""",
- )
- D = DBItem(
- 17,
- """
- D
+def gpg_algorithm_letter(algorithm):
+ """Return a single letter describing a GPG public key algorithm.
- DSA""",
- )
+ This can be used in display names of keys.
- G = DBItem(
- 20,
- """
- G
-
- ElGamal, compromised""",
- )
-
- ECDSA = DBItem(
- 301,
- """
- E
-
- ECDSA""",
- )
-
- ECDH = DBItem(
- 302,
- """
- e
-
- ECDH""",
- )
+ See `pubkey_letter` in GnuPG
+ (https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=g10/keyid.c)
+ for the single-letter codes used here. Note that they are not
+ necessarily unique.
+ """
+ if algorithm == GPGKeyAlgorithm.R:
+ return "R"
+ elif algorithm == GPGKeyAlgorithm.LITTLE_G:
+ return "g"
+ elif algorithm == GPGKeyAlgorithm.D:
+ return "D"
+ elif algorithm == GPGKeyAlgorithm.G:
+ return "G"
+ elif algorithm in (GPGKeyAlgorithm.ECDSA, GPGKeyAlgorithm.EDDSA):
+ return "E"
+ elif algorithm == GPGKeyAlgorithm.ECDH:
+ return "e"
class MoreThanOneGPGKeyFound(Exception):
diff --git a/lib/lp/services/gpg/tests/test_gpghandler.py b/lib/lp/services/gpg/tests/test_gpghandler.py
index 1199ea0..834d91b 100644
--- a/lib/lp/services/gpg/tests/test_gpghandler.py
+++ b/lib/lp/services/gpg/tests/test_gpghandler.py
@@ -19,6 +19,7 @@ from lp.services.features.testing import FeatureFixture
from lp.services.gpg.handler import signing_only_param
from lp.services.gpg.interfaces import (
GPG_INJECT,
+ GPGKeyAlgorithm,
GPGKeyDoesNotExistOnServer,
GPGKeyMismatchOnServer,
GPGKeyTemporarilyNotFoundError,
@@ -407,7 +408,7 @@ class TestGPGHandler(TestCase):
new_key,
MatchesStructure(
secret=Is(True),
- algorithm=MatchesStructure.byEquality(title="R"),
+ algorithm=Equals(GPGKeyAlgorithm.R),
keysize=Equals(1024),
can_sign=Is(True),
can_encrypt=Is(False),
@@ -433,7 +434,7 @@ class TestGPGHandler(TestCase):
pub_key,
MatchesStructure(
secret=Is(False),
- algorithm=MatchesStructure.byEquality(title="R"),
+ algorithm=Equals(GPGKeyAlgorithm.R),
keysize=Equals(1024),
can_sign=Is(True),
can_encrypt=Is(False),
diff --git a/lib/lp/services/verification/model/logintoken.py b/lib/lp/services/verification/model/logintoken.py
index 03a5bc6..eea34dd 100644
--- a/lib/lp/services/verification/model/logintoken.py
+++ b/lib/lp/services/verification/model/logintoken.py
@@ -25,7 +25,7 @@ from lp.services.database.constants import UTC_NOW
from lp.services.database.enumcol import DBEnum
from lp.services.database.interfaces import IPrimaryStore, IStore
from lp.services.database.stormbase import StormBase
-from lp.services.gpg.interfaces import IGPGHandler
+from lp.services.gpg.interfaces import IGPGHandler, gpg_algorithm_letter
from lp.services.mail.helpers import get_email_template
from lp.services.mail.sendmail import format_address, simple_sendmail
from lp.services.tokens import create_token
@@ -172,7 +172,7 @@ class LoginToken(StormBase):
# Here are the instructions that need to be encrypted.
template = get_email_template("validate-gpg.txt", app=MAIL_APP)
- key_type = "%s%s" % (key.keysize, key.algorithm.title)
+ key_type = "%s%s" % (key.keysize, gpg_algorithm_letter(key.algorithm))
replacements = {
"requester": self.requester.displayname,
"requesteremail": self.requesteremail,
diff --git a/lib/lp/soyuz/browser/tests/test_personal_archive_subscription.py b/lib/lp/soyuz/browser/tests/test_personal_archive_subscription.py
index 1151c37..80f973b 100644
--- a/lib/lp/soyuz/browser/tests/test_personal_archive_subscription.py
+++ b/lib/lp/soyuz/browser/tests/test_personal_archive_subscription.py
@@ -47,8 +47,8 @@ class TestPersonArchiveSubscriptionView(TestCaseWithFactory):
view = create_initialized_view(pas, "+index", principal=subscriber)
signing_key = find_tag_by_id(view(), "signing-key")
self.assertEqual(
- "This repository is signed with\n%s%s/%s OpenPGP key."
- % (key.keysize, key.algorithm.title, key.fingerprint),
+ "This repository is signed with\n%s OpenPGP key."
+ % key.displayname,
extract_text(signing_key),
)
self.assertEqual(
diff --git a/lib/lp/soyuz/model/archive.py b/lib/lp/soyuz/model/archive.py
index c7749ba..b86c2e9 100644
--- a/lib/lp/soyuz/model/archive.py
+++ b/lib/lp/soyuz/model/archive.py
@@ -481,11 +481,7 @@ class Archive(StormBase):
self.signing_key_fingerprint,
)
else:
- return "%s%s/%s" % (
- pyme_key.keysize,
- pyme_key.algorithm.title,
- pyme_key.fingerprint,
- )
+ return pyme_key.displayname
@property
def is_ppa(self):