← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~lgp171188/launchpad:serve-rsa4096-when-archive-also-has-rsa1024-key into launchpad:master

 

Guruprasad has proposed merging ~lgp171188/launchpad:serve-rsa4096-when-archive-also-has-rsa1024-key into launchpad:master.

Commit message:
Add a garbo job to switch the served signing key fingerprint of PPAs

When a PPA has an rsa1024 signing key and rsa4096 signing key, this job
will update `IArchive.signing_key_fingerprint` to point to the latter,
thereby making the default more secure.


Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~lgp171188/launchpad/+git/launchpad/+merge/470160
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~lgp171188/launchpad:serve-rsa4096-when-archive-also-has-rsa1024-key into launchpad:master.
diff --git a/lib/lp/scripts/garbo.py b/lib/lp/scripts/garbo.py
index d4fa136..63bc5b7 100644
--- a/lib/lp/scripts/garbo.py
+++ b/lib/lp/scripts/garbo.py
@@ -67,6 +67,7 @@ from lp.code.model.revisionstatus import RevisionStatusArtifact
 from lp.oci.model.ocirecipebuild import OCIFile
 from lp.registry.interfaces.person import IPersonSet
 from lp.registry.model.distribution import Distribution
+from lp.registry.model.gpgkey import GPGKey
 from lp.registry.model.person import Person
 from lp.registry.model.product import Product
 from lp.registry.model.sourcepackagename import SourcePackageName
@@ -112,6 +113,7 @@ from lp.services.scripts.base import (
     SilentLaunchpadScriptFailure,
 )
 from lp.services.session.model import SessionData
+from lp.services.signing.interfaces.signingkey import IArchiveSigningKeySet
 from lp.services.verification.model.logintoken import LoginToken
 from lp.services.webapp.publisher import canonical_url
 from lp.services.webhooks.interfaces import IWebhookJobSource
@@ -120,6 +122,7 @@ from lp.snappy.model.snapbuild import SnapFile
 from lp.snappy.model.snapbuildjob import SnapBuildJobType
 from lp.soyuz.enums import (
     ArchivePublishingMethod,
+    ArchivePurpose,
     ArchiveRepositoryFormat,
     ArchiveSubscriberStatus,
 )
@@ -2259,6 +2262,53 @@ class ArchiveFileDatePopulator(TunableLoop):
         transaction.commit()
 
 
+class UpdatePPASigningKeyFingerprintToRSA4096Key(TunableLoop):
+    """
+    Update the signing key fingerprint of archives with an rsa1024
+    signing key and an rsa4096 signing key to be the fingerprint of
+    the rsa4096 signing key.
+    """
+
+    maximum_chunk_size = 1000
+
+    def __init__(self, log, abort_time=None):
+        super().__init__(log, abort_time)
+        self.store = IPrimaryStore(Archive)
+        self.start_at = 1
+
+    def findAffectedArchives(self):
+        join = (
+            Archive,
+            Join(
+                GPGKey,
+                GPGKey.fingerprint == Archive.signing_key_fingerprint,
+            ),
+        )
+        return (
+            self.store.using(*join)
+            .find(
+                Archive,
+                Archive.purpose == ArchivePurpose.PPA,
+                GPGKey.keysize == 1024,
+            )
+            .order_by(Archive.id)
+        )
+
+    def updateSigningKeyFingerprint(self, archive):
+        archive_signing_key_set = getUtility(IArchiveSigningKeySet)
+        rsa4096_key = archive_signing_key_set.get4096BitRSASigningKey(archive)
+        if rsa4096_key:
+            archive.signing_key_fingerprint = rsa4096_key.fingerprint
+
+    def isDone(self):
+        return self.findAffectedArchives().is_empty()
+
+    def __call__(self, chunk_size):
+        for archive in self.findAffectedArchives()[:chunk_size]:
+            self.updateSigningKeyFingerprint(archive)
+        transaction.commit()
+
+
 class BaseDatabaseGarbageCollector(LaunchpadCronScript):
     """Abstract base class to run a collection of TunableLoops."""
 
@@ -2550,6 +2600,7 @@ class HourlyDatabaseGarbageCollector(BaseDatabaseGarbageCollector):
         GitRepositoryPruner,
         RevisionCachePruner,
         UnusedSessionPruner,
+        UpdatePPASigningKeyFingerprintToRSA4096Key,
     ]
     experimental_tunable_loops = []
 
diff --git a/lib/lp/scripts/tests/test_garbo.py b/lib/lp/scripts/tests/test_garbo.py
index a5a16e0..85563a0 100644
--- a/lib/lp/scripts/tests/test_garbo.py
+++ b/lib/lp/scripts/tests/test_garbo.py
@@ -82,6 +82,7 @@ from lp.scripts.garbo import (
     ProductVCSPopulator,
     UnusedPOTMsgSetPruner,
     UnusedSessionPruner,
+    UpdatePPASigningKeyFingerprintToRSA4096Key,
     load_garbo_job_state,
     save_garbo_job_state,
 )
@@ -106,6 +107,7 @@ from lp.services.messages.interfaces.message import IMessageSet
 from lp.services.messages.model.message import Message
 from lp.services.openid.model.openidconsumer import OpenIDConsumerNonce
 from lp.services.session.model import SessionData, SessionPkgData
+from lp.services.signing.enums import SigningKeyType
 from lp.services.verification.interfaces.authtoken import LoginTokenType
 from lp.services.verification.model.logintoken import LoginToken
 from lp.services.worlddata.interfaces.language import ILanguageSet
@@ -2584,6 +2586,41 @@ class TestGarbo(FakeAdapterMixin, TestCaseWithFactory):
         self.assertEqual(1, rs.count())
         self.assertEqual(archive_files[1], rs.one())
 
+    def test_UpdatePPASigningKeyFingerprintToRSA4096Key(self):
+        switch_dbuser("testadmin")
+        person = self.factory.makePerson()
+        archive = self.factory.makeArchive(owner=person)
+        rsa1024_gpg_key = self.factory.makeGPGKey(owner=person, keysize=1024)
+        archive.signing_key_fingerprint = rsa1024_gpg_key.fingerprint
+        rsa4096_gpg_key = self.factory.makeGPGKey(owner=person, keysize=4096)
+        rsa4096_signing_key = self.factory.makeSigningKey(
+            key_type=SigningKeyType.OPENPGP,
+            fingerprint=rsa4096_gpg_key.fingerprint,
+        )
+        self.factory.makeArchiveSigningKey(archive, None, rsa4096_signing_key)
+
+        archive_2 = self.factory.makeArchive()
+        rsa1024_gpg_key_2 = self.factory.makeGPGKey(owner=person, keysize=1024)
+        archive_2.signing_key_fingerprint = rsa1024_gpg_key_2.fingerprint
+        rsa4096_gpg_key_2 = self.factory.makeGPGKey(owner=person, keysize=4096)
+        rsa4096_signing_key_2 = self.factory.makeSigningKey(
+            key_type=SigningKeyType.OPENPGP,
+            fingerprint=rsa4096_gpg_key_2.fingerprint,
+        )
+        self.factory.makeArchiveSigningKey(
+            archive_2, None, rsa4096_signing_key_2
+        )
+        updater = UpdatePPASigningKeyFingerprintToRSA4096Key(log=None)
+        self.assertEqual(2, updater.findAffectedArchives().count())
+        self.runHourly()
+        self.assertTrue(updater.findAffectedArchives().is_empty())
+        self.assertEqual(
+            rsa4096_gpg_key.fingerprint, archive.signing_key_fingerprint
+        )
+        self.assertEqual(
+            rsa4096_gpg_key_2.fingerprint, archive_2.signing_key_fingerprint
+        )
+
 
 class TestGarboTasks(TestCaseWithFactory):
     layer = LaunchpadZopelessLayer

References