Skip to content

Commit

Permalink
move certs/timestamps to constants
Browse files Browse the repository at this point in the history
  • Loading branch information
mathiasertl committed Oct 14, 2023
1 parent 3428e99 commit 1c39202
Show file tree
Hide file tree
Showing 56 changed files with 948 additions and 985 deletions.
12 changes: 10 additions & 2 deletions ca/django_ca/extensions/serialize.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,15 @@
# You should have received a copy of the GNU General Public License along with django-ca. If not, see
# <http://www.gnu.org/licenses/>.

"""``django_ca.extensions.serialize`` contains functions to serialize extensions."""
"""``django_ca.extensions.serialize`` contains functions to serialize extensions.
NOTE::
Functions in this module return values in the order as they appear in the extensions, so that the original
extension can be reconstructed exactly from this serialized form.
TODO:: Make sure the above is actually true.
"""

import binascii
from typing import Any, Dict, List, Optional
Expand Down Expand Up @@ -191,7 +199,7 @@ def _serialize_extension( # pylint: disable=too-many-return-statements
if isinstance(value, x509.CertificatePolicies):
return _certificate_policies_serialized(value)
if isinstance(value, x509.ExtendedKeyUsage):
return sorted([EXTENDED_KEY_USAGE_NAMES[usage] for usage in value])
return [EXTENDED_KEY_USAGE_NAMES[usage] for usage in value]
if isinstance(value, x509.InhibitAnyPolicy):
return value.skip_certs
if isinstance(value, x509.KeyUsage):
Expand Down
11 changes: 7 additions & 4 deletions ca/django_ca/tests/acme/views/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@

from django_ca.acme.responses import AcmeResponseUnauthorized
from django_ca.models import AcmeAccount, CertificateAuthority, acme_slug
from django_ca.tests.base import certs, override_tmpcadir
from django_ca.tests.base import override_tmpcadir
from django_ca.tests.base.constants import CERT_DATA
from django_ca.tests.base.mixins import TestCaseMixin

MessageTypeVar = typing.TypeVar("MessageTypeVar", bound=jose.json_util.JSONObjectWithFields)
Expand All @@ -51,7 +52,7 @@ class AcmeTestCaseMixin(TestCaseMixin):

# NOTE: PEM here is the same as AcmeAccount.pem when this cert is used for account registration
PEM = (
certs["root-cert"]["key"]["parsed"]
CERT_DATA["root-cert"]["key"]["parsed"]
.public_key()
.public_bytes(Encoding.PEM, PublicFormat.SubjectPublicKeyInfo)
.decode("utf-8")
Expand All @@ -60,7 +61,7 @@ class AcmeTestCaseMixin(TestCaseMixin):
thumbprint = "kqtZjXqX07HbrRg220VoINzqF9QXsfIkQava3PdWM8o"
ACCOUNT_ONE_CONTACT = "mailto:[email protected]"
CHILD_PEM = (
certs["child-cert"]["key"]["parsed"]
CERT_DATA["child-cert"]["key"]["parsed"]
.public_key()
.public_bytes(Encoding.PEM, PublicFormat.SubjectPublicKeyInfo)
.decode("utf-8")
Expand Down Expand Up @@ -238,7 +239,9 @@ def acme(
if nonce is None:
nonce = self.get_nonce()
if cert is None:
cert = typing.cast(CertificateIssuerPrivateKeyTypes, certs[self.load_certs[0]]["key"]["parsed"])
cert = typing.cast(
CertificateIssuerPrivateKeyTypes, CERT_DATA[self.load_certs[0]]["key"]["parsed"]
)
if post_kwargs is None:
post_kwargs = {}

Expand Down
5 changes: 3 additions & 2 deletions ca/django_ca/tests/acme/views/test_authorization.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@
from django_ca import ca_settings
from django_ca.models import AcmeAuthorization, AcmeChallenge, AcmeOrder
from django_ca.tests.acme.views.base import AcmeWithAccountViewTestCaseMixin
from django_ca.tests.base import override_tmpcadir, timestamps
from django_ca.tests.base import override_tmpcadir
from django_ca.tests.base.constants import TIMESTAMPS


@freeze_time(timestamps["everything_valid"])
@freeze_time(TIMESTAMPS["everything_valid"])
class AcmeAuthorizationViewTestCase(
AcmeWithAccountViewTestCaseMixin[jose.json_util.JSONObjectWithFields], TestCase
):
Expand Down
5 changes: 3 additions & 2 deletions ca/django_ca/tests/acme/views/test_challenge.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@
from django_ca.models import AcmeAuthorization, AcmeChallenge, AcmeOrder
from django_ca.tasks import acme_validate_challenge
from django_ca.tests.acme.views.base import AcmeWithAccountViewTestCaseMixin
from django_ca.tests.base import override_tmpcadir, timestamps
from django_ca.tests.base import override_tmpcadir
from django_ca.tests.base.constants import TIMESTAMPS


@freeze_time(timestamps["everything_valid"])
@freeze_time(TIMESTAMPS["everything_valid"])
class AcmeChallengeViewTestCase(
AcmeWithAccountViewTestCaseMixin[jose.json_util.JSONObjectWithFields], TransactionTestCase
):
Expand Down
14 changes: 7 additions & 7 deletions ca/django_ca/tests/acme/views/test_directory.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from freezegun import freeze_time

from django_ca.models import CertificateAuthority
from django_ca.tests.base import timestamps
from django_ca.tests.base.constants import TIMESTAMPS
from django_ca.tests.base.mixins import TestCaseMixin


Expand All @@ -39,7 +39,7 @@ def setUp(self) -> None:
self.ca.acme_enabled = True
self.ca.save()

@freeze_time(timestamps["everything_valid"])
@freeze_time(TIMESTAMPS["everything_valid"])
def test_default(self) -> None:
"""Test the default directory view."""
with mock.patch("secrets.token_bytes", return_value=b"foobar"):
Expand All @@ -58,7 +58,7 @@ def test_default(self) -> None:
},
)

@freeze_time(timestamps["everything_valid"])
@freeze_time(TIMESTAMPS["everything_valid"])
def test_named_ca(self) -> None:
"""Test getting directory for named CA."""
url = reverse("django_ca:acme-directory", kwargs={"serial": self.ca.serial})
Expand All @@ -79,7 +79,7 @@ def test_named_ca(self) -> None:
},
)

@freeze_time(timestamps["everything_valid"])
@freeze_time(TIMESTAMPS["everything_valid"])
def test_meta(self) -> None:
"""Test the meta property."""
self.ca.website = "http://ca.example.com"
Expand Down Expand Up @@ -112,7 +112,7 @@ def test_meta(self) -> None:
},
)

@freeze_time(timestamps["everything_valid"])
@freeze_time(TIMESTAMPS["everything_valid"])
def test_acme_default_disabled(self) -> None:
"""Test that fetching the default CA with ACME disabled doesn't work."""
self.ca.acme_enabled = False
Expand All @@ -130,7 +130,7 @@ def test_acme_default_disabled(self) -> None:
},
)

@freeze_time(timestamps["everything_valid"])
@freeze_time(TIMESTAMPS["everything_valid"])
def test_acme_disabled(self) -> None:
"""Test that fetching the default CA with ACME disabled doesn't work."""
self.ca.acme_enabled = False
Expand Down Expand Up @@ -164,7 +164,7 @@ def test_no_ca(self) -> None:
},
)

@freeze_time(timestamps["everything_expired"])
@freeze_time(TIMESTAMPS["everything_expired"])
def test_expired_ca(self) -> None:
"""Test using default CA when all CAs are expired."""
response = self.client.get(self.url)
Expand Down
7 changes: 4 additions & 3 deletions ca/django_ca/tests/acme/views/test_new_account.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,16 @@

from django_ca.models import AcmeAccount
from django_ca.tests.acme.views.base import AcmeBaseViewTestCaseMixin
from django_ca.tests.base import certs, override_tmpcadir, timestamps
from django_ca.tests.base import override_tmpcadir
from django_ca.tests.base.constants import CERT_DATA, TIMESTAMPS


@freeze_time(timestamps["everything_valid"])
@freeze_time(TIMESTAMPS["everything_valid"])
class AcmeNewAccountViewTestCase(AcmeBaseViewTestCaseMixin[acme.messages.Registration], TestCase):
"""Test creating a new account."""

contact = "mailto:[email protected]"
url = reverse_lazy("django_ca:acme-new-account", kwargs={"serial": certs["root"]["serial"]})
url = reverse_lazy("django_ca:acme-new-account", kwargs={"serial": CERT_DATA["root"]["serial"]})
message = acme.messages.Registration(contact=(contact,), terms_of_service_agreed=True)
message_cls = acme.messages.Registration
requires_kid = False
Expand Down
7 changes: 4 additions & 3 deletions ca/django_ca/tests/acme/views/test_new_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,15 @@
from django_ca.acme.messages import NewOrder
from django_ca.models import AcmeAuthorization, AcmeOrder
from django_ca.tests.acme.views.base import AcmeWithAccountViewTestCaseMixin
from django_ca.tests.base import certs, override_tmpcadir, timestamps
from django_ca.tests.base import override_tmpcadir
from django_ca.tests.base.constants import CERT_DATA, TIMESTAMPS


@freeze_time(timestamps["everything_valid"])
@freeze_time(TIMESTAMPS["everything_valid"])
class AcmeNewOrderViewTestCase(AcmeWithAccountViewTestCaseMixin[NewOrder], TestCase):
"""Test creating a new order."""

url = reverse_lazy("django_ca:acme-new-order", kwargs={"serial": certs["root"]["serial"]})
url = reverse_lazy("django_ca:acme-new-order", kwargs={"serial": CERT_DATA["root"]["serial"]})
message_cls = NewOrder

def get_message(self, **kwargs: Any) -> NewOrder:
Expand Down
5 changes: 3 additions & 2 deletions ca/django_ca/tests/acme/views/test_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@
from django_ca.acme.errors import AcmeUnauthorized
from django_ca.models import AcmeAccount, AcmeAuthorization, AcmeCertificate, AcmeOrder
from django_ca.tests.acme.views.base import AcmeWithAccountViewTestCaseMixin
from django_ca.tests.base import override_tmpcadir, timestamps
from django_ca.tests.base import override_tmpcadir
from django_ca.tests.base.constants import TIMESTAMPS


@freeze_time(timestamps["everything_valid"])
@freeze_time(TIMESTAMPS["everything_valid"])
class AcmeOrderViewTestCase(AcmeWithAccountViewTestCaseMixin[jose.json_util.JSONObjectWithFields], TestCase):
"""Test retrieving an order."""

Expand Down
22 changes: 11 additions & 11 deletions ca/django_ca/tests/acme/views/test_order_finalize.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,20 @@
from django_ca.models import AcmeAccount, AcmeAuthorization, AcmeOrder
from django_ca.tasks import acme_issue_certificate
from django_ca.tests.acme.views.base import AcmeWithAccountViewTestCaseMixin
from django_ca.tests.base import certs, dns, override_tmpcadir, timestamps
from django_ca.tests.base.constants import FIXTURES_DIR
from django_ca.tests.base import dns, override_tmpcadir
from django_ca.tests.base.constants import CERT_DATA, FIXTURES_DIR, TIMESTAMPS
from django_ca.tests.base.typehints import HttpResponse


@freeze_time(timestamps["everything_valid"])
@freeze_time(TIMESTAMPS["everything_valid"])
class AcmeOrderFinalizeViewTestCase(
AcmeWithAccountViewTestCaseMixin[CertificateRequest], TransactionTestCase
):
"""Test retrieving a challenge."""

slug = "92MPyl7jm0zw"
url = reverse_lazy(
"django_ca:acme-order-finalize", kwargs={"serial": certs["root"]["serial"], "slug": slug}
"django_ca:acme-order-finalize", kwargs={"serial": CERT_DATA["root"]["serial"], "slug": slug}
)

def setUp(self) -> None:
Expand All @@ -59,7 +59,7 @@ def setUp(self) -> None:
x509.CertificateSigningRequestBuilder()
.subject_name(x509.Name([]))
.add_extension(x509.SubjectAlternativeName([dns(self.hostname)]), critical=False)
.sign(certs["root-cert"]["key"]["parsed"], hashes.SHA256())
.sign(CERT_DATA["root-cert"]["key"]["parsed"], hashes.SHA256())
)

self.order = AcmeOrder.objects.create(
Expand Down Expand Up @@ -213,7 +213,7 @@ def test_csr_valid_subject(self) -> None:
)
)
.add_extension(x509.SubjectAlternativeName([dns(self.hostname)]), critical=False)
.sign(certs["root-cert"]["key"]["parsed"], hashes.SHA256())
.sign(CERT_DATA["root-cert"]["key"]["parsed"], hashes.SHA256())
)

with self.patch("django_ca.acme.views.run_task") as mockcm:
Expand Down Expand Up @@ -249,7 +249,7 @@ def test_csr_subject_no_cn(self) -> None:
)
)
.add_extension(x509.SubjectAlternativeName([dns(self.hostname)]), critical=False)
.sign(certs["root-cert"]["key"]["parsed"], hashes.SHA256())
.sign(CERT_DATA["root-cert"]["key"]["parsed"], hashes.SHA256())
)

with self.patch("django_ca.acme.views.run_task") as mockcm:
Expand Down Expand Up @@ -285,7 +285,7 @@ def test_csr_subject_no_domain(self) -> None:
)
)
.add_extension(x509.SubjectAlternativeName([dns(self.hostname)]), critical=False)
.sign(certs["root-cert"]["key"]["parsed"], hashes.SHA256())
.sign(CERT_DATA["root-cert"]["key"]["parsed"], hashes.SHA256())
)

with self.patch("django_ca.acme.views.run_task") as mockcm:
Expand All @@ -306,7 +306,7 @@ def test_csr_subject_not_in_order(self) -> None:
)
)
.add_extension(x509.SubjectAlternativeName([dns(self.hostname)]), critical=False)
.sign(certs["root-cert"]["key"]["parsed"], hashes.SHA256())
.sign(CERT_DATA["root-cert"]["key"]["parsed"], hashes.SHA256())
)

with self.patch("django_ca.acme.views.run_task") as mockcm:
Expand All @@ -320,7 +320,7 @@ def test_csr_no_san(self) -> None:
csr = (
x509.CertificateSigningRequestBuilder()
.subject_name(x509.Name([]))
.sign(certs["root-cert"]["key"]["parsed"], hashes.SHA256())
.sign(CERT_DATA["root-cert"]["key"]["parsed"], hashes.SHA256())
)

with self.patch("django_ca.acme.views.run_task") as mockcm:
Expand All @@ -338,7 +338,7 @@ def test_csr_different_names(self) -> None:
x509.SubjectAlternativeName([dns(self.hostname), dns("example.net")]),
critical=False,
)
.sign(certs["root-cert"]["key"]["parsed"], hashes.SHA256())
.sign(CERT_DATA["root-cert"]["key"]["parsed"], hashes.SHA256())
)

with self.patch("django_ca.acme.views.run_task") as mockcm:
Expand Down
25 changes: 13 additions & 12 deletions ca/django_ca/tests/acme/views/test_revocation.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,13 @@
from django_ca.constants import ReasonFlags
from django_ca.models import AcmeAccount, AcmeAuthorization, AcmeCertificate, AcmeOrder, Certificate
from django_ca.tests.acme.views.base import AcmeWithAccountViewTestCaseMixin
from django_ca.tests.base import certs, override_tmpcadir, timestamps
from django_ca.tests.base import override_tmpcadir
from django_ca.tests.base.constants import CERT_DATA, TIMESTAMPS
from django_ca.tests.base.typehints import HttpResponse
from django_ca.utils import get_cert_builder


@freeze_time(timestamps["everything_valid"])
@freeze_time(TIMESTAMPS["everything_valid"])
class AcmeCertificateRevocationViewTestCase(
AcmeWithAccountViewTestCaseMixin[acme.messages.Revocation], TestCase
):
Expand Down Expand Up @@ -80,7 +81,7 @@ def test_basic(self) -> None:

self.cert.refresh_from_db()
self.assertTrue(self.cert.revoked)
self.assertEqual(self.cert.revoked_date, timestamps["everything_valid"])
self.assertEqual(self.cert.revoked_date, TIMESTAMPS["everything_valid"])
self.assertEqual(self.cert.revoked_reason, ReasonFlags.unspecified.value)

@override_settings(USE_TZ=False)
Expand All @@ -91,7 +92,7 @@ def test_basic_with_use_tz_false(self) -> None:

self.cert.refresh_from_db()
self.assertTrue(self.cert.revoked)
self.assertEqual(self.cert.revoked_date, timestamps["everything_valid_naive"])
self.assertEqual(self.cert.revoked_date, TIMESTAMPS["everything_valid_naive"])
self.assertEqual(self.cert.revoked_reason, ReasonFlags.unspecified.value)

def test_reason_code(self) -> None:
Expand All @@ -102,7 +103,7 @@ def test_reason_code(self) -> None:

self.cert.refresh_from_db()
self.assertTrue(self.cert.revoked)
self.assertEqual(self.cert.revoked_date, timestamps["everything_valid"])
self.assertEqual(self.cert.revoked_date, TIMESTAMPS["everything_valid"])
self.assertEqual(self.cert.revoked_reason, ReasonFlags.affiliation_changed.name)

def test_already_revoked(self) -> None:
Expand Down Expand Up @@ -132,7 +133,7 @@ def test_unknown_certificate(self) -> None:
def test_wrong_certificate(self) -> None:
"""Test sending a different certificate with the same serial."""
# Create a clone of the existing certificate with the same serial number
pkey = certs["root-cert"]["csr"]["parsed"].public_key()
pkey = CERT_DATA["root-cert"]["csr"]["parsed"].public_key()
builder = get_cert_builder(self.cert.expires, serial=self.cert.pub.loaded.serial_number)
builder = builder.public_key(pkey)
builder = builder.issuer_name(self.ca.subject)
Expand All @@ -147,13 +148,13 @@ def test_wrong_certificate(self) -> None:

def test_pass_csr(self) -> None:
"""Send a CSR instead of a certificate."""
req = X509Req.from_cryptography(certs["root-cert"]["csr"]["parsed"])
req = X509Req.from_cryptography(CERT_DATA["root-cert"]["csr"]["parsed"])
message = self.csr_class(certificate=jose.util.ComparableX509(req))
resp = self.acme(self.url, message, kid=self.kid)
self.assertMalformed(resp, "Could not decode 'certificate'", regex=True)


@freeze_time(timestamps["everything_valid"])
@freeze_time(TIMESTAMPS["everything_valid"])
class AcmeCertificateRevocationWithAuthorizationsViewTestCase(AcmeCertificateRevocationViewTestCase):
"""Test certificate revocation by signing the request with the compromised certificate."""

Expand All @@ -166,7 +167,7 @@ def setUp(self) -> None:
)

def acme(self, *args: Any, **kwargs: Any) -> "HttpResponse":
kwargs.setdefault("cert", certs["child-cert"]["key"]["parsed"])
kwargs.setdefault("cert", CERT_DATA["child-cert"]["key"]["parsed"])
kwargs["kid"] = self.child_kid
return super().acme(*args, **kwargs)

Expand Down Expand Up @@ -210,20 +211,20 @@ def test_non_dns_sans(self) -> None:
self.assertUnauthorized(resp, "Certificate contains non-DNS subjectAlternativeNames.")


@freeze_time(timestamps["everything_valid"])
@freeze_time(TIMESTAMPS["everything_valid"])
class AcmeCertificateRevocationWithJWKViewTestCase(AcmeCertificateRevocationViewTestCase):
"""Test certificate revocation by signing the request with the compromised certificate."""

requires_kid = False

def acme(self, *args: Any, **kwargs: Any) -> "HttpResponse":
kwargs.setdefault("cert", certs[self.default_cert]["key"]["parsed"])
kwargs.setdefault("cert", CERT_DATA[self.default_cert]["key"]["parsed"])
kwargs["kid"] = None
return super().acme(*args, **kwargs)

def test_wrong_signer(self) -> None:
"""Sign the request with the wrong certificate."""
cert = certs["root-cert"]["key"]["parsed"]
cert = CERT_DATA["root-cert"]["key"]["parsed"]
resp = self.acme(self.url, self.message, cert=cert)
self.assertUnauthorized(resp, "Request signed by the wrong certificate.")

Expand Down
Loading

0 comments on commit 1c39202

Please sign in to comment.