Commit 6e6ef842 authored by Raphaël Hertzog's avatar Raphaël Hertzog

utils: improve verify_signature() to return better user identities

Up to now it always returned the first UID on the key. Unfortunately,
that UID was sometimes an UID without email (or with an invalid email)
which in turn generated invalid emails in the database. Also the primary
UID is not often the Debian UID so we returned personal emails when we
could have found the proper Debian identity.

So now, we do a first pass looking for an email that matches the domain
name of the tracker installation. If it's not succesfull, we return the
first valid non-revoked UID with a valid email.
parent 5556dac7
Pipeline #68344 failed with stages
in 10 minutes and 2 seconds
-----BEGIN PGP PUBLIC KEY BLOCK-----
Comment: Signed by Raphael Hertzog
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
tIWRlNPl60LyzX04BjoFjnMnjMO5
=WdOP
-----END PGP PUBLIC KEY BLOCK-----
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
This is another test with a key without emails.
-----BEGIN PGP SIGNATURE-----
Comment: Signed by Raphael Hertzog
iQGzBAEBCgAdFiEEmQh8X5R4z3jS39QUGrAyeYoF0D8FAl1qb1wACgkQGrAyeYoF
0D95ZAv+MnFCNL00h1ZNjf63CR/6XrkiiJDlx5kIe0+KdLwK05LfcfqOGPeXb7Aj
7194qwEaNVEoQ2z6RYCZkkv1UfLDCcGr+bujdYEHKYNCKuTMsYL5B2FW5wFzy4Dh
tNZ3P4vE0e1m0HdbCIZa7bFozzda90SnBu7x2sNuP6VK7kMvbnU67blHrDtpGTNo
YbTsKG8jWbEwG3J6MO4HAIqirtlz7tfDR9mawXnDMc+M+dktWUUaBgaZDLCWFoRU
AFzMjCKhpo4h9hDNZYnNj6QG6awNVWWd0YY3d0+vZmgXaUBUN8aKosLZ3vLeo0aV
lwuycMQ+MLkWplNUOsdaqidvQjyuzPPwcS2i26cU37Fz92SI5GFdSGjLdKSz8Dqg
L9OST/r9hX9N9kN3r2QIn7zWk/wjpFNBeudxmx2yq4URIYaZoRKG7uT9+6w3KMa8
TvjaWMShWgoMvGtZzuKS36LcbiDVny7cJ1tfN9o08mFivnDVHCPYwIEvyUoYArXh
zagsrrFo
=wkiq
-----END PGP SIGNATURE-----
......@@ -1225,6 +1225,51 @@ class VerifySignatureTest(SimpleTestCase):
content = f.read().decode('utf-8')
self.assertEqual(expected, verify_signature(content))
@override_settings(DISTRO_TRACKER_FQDN='random.unrelated.domain')
def test_uid_with_invalid_email_is_skipped(self):
"""
Among all the available UID, make sure we skip those without email
or with invalid emails.
"""
# The invalid UID have been put first in the list of UIDs on that key
self.import_key_into_keyring('key2.pub')
file_path = self.get_test_data_path('signed-message-with-key2')
expected = [
('John Doe', 'test@ouaza.com')
]
with open(file_path, 'rb') as f:
self.assertEqual(expected, verify_signature(f.read()))
@override_settings(DISTRO_TRACKER_FQDN='tracker.debian.org')
def test_uid_with_project_domain_is_preferred(self):
"""
If we have an UID using the same domain name as this instance,
then prefer that UID.
"""
self.import_key_into_keyring('key2.pub')
file_path = self.get_test_data_path('signed-message-with-key2')
expected = [
('John Debian', 'test@debian.org')
]
with open(file_path, 'rb') as f:
self.assertEqual(expected, verify_signature(f.read()))
@override_settings(DISTRO_TRACKER_FQDN='tracker.revoked.net')
def test_skip_revoked_uid_with_project_domain(self):
"""Ensure that we ignore invalid and revoked UIDs."""
self.import_key_into_keyring('key2.pub')
file_path = self.get_test_data_path('signed-message-with-key2')
# We do have an UID in @revoked.net but it's not selected, instead
# we get the first key with a valid email.
expected = [
('John Doe', 'test@ouaza.com')
]
with open(file_path, 'rb') as f:
self.assertEqual(expected, verify_signature(f.read()))
class DecodeHeaderTest(SimpleTestCase):
"""
......
# Copyright 2013-2018 The Distro Tracker Developers
# Copyright 2013-2019 The Distro Tracker Developers
# See the COPYRIGHT file at the top-level directory of this distribution and
# at https://deb.li/DTAuthors
#
......@@ -13,6 +13,8 @@ import json
import os
from django.conf import settings
from django.core.exceptions import ValidationError
from django.core.validators import EmailValidator
from django.db import models
from django.http import HttpResponse
from django.template.loader import render_to_string
......@@ -244,11 +246,43 @@ def verify_signature(content):
continue
key = ctx.get_key(signature.fpr)
signers.append((key.uids[0].name, key.uids[0].email))
preferred_domain = "".join(
settings.DISTRO_TRACKER_FQDN.split(".", 1)[1:2])
selected_uid = _select_uid_in_key(key, domain=preferred_domain)
if not selected_uid:
selected_uid = _select_uid_in_key(key)
signers.append((selected_uid.name, selected_uid.email))
return signers
def _select_uid_in_key(key, domain=None):
"""
Select the desired UID among all the available UIDs.
"""
selected_uid = None
validate_email = EmailValidator()
for uid in key.uids:
if uid.revoked or uid.invalid:
continue
try:
validate_email(uid.email)
if domain:
if uid.email.endswith('@' + domain):
selected_uid = uid
break
else:
selected_uid = uid
break
except ValidationError:
continue
return selected_uid
def now(tz=datetime.timezone.utc):
"""
Returns the current timestamp in the requested timezone (UTC by default)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment