Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
792 changes: 551 additions & 241 deletions django_x509/base/models.py

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
# Generated by Django 5.2.7 on 2025-10-06 08:11

import collections
import django_x509.base.models
import jsonfield.fields
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("django_x509", "0009_alter_ca_digest_alter_ca_key_length_and_more"),
]

operations = [
migrations.AlterField(
model_name="ca",
name="certificate",
field=models.TextField(
blank=True, help_text="Certificate in X.509 PEM format"
),
),
migrations.AlterField(
model_name="ca",
name="digest",
field=models.CharField(
choices=[
("sha1WithRSAEncryption", "SHA1 with RSA signature"),
("sha224WithRSAEncryption", "SHA224 with RSA signature"),
("sha256WithRSAEncryption", "SHA256 with RSA signature"),
("sha384WithRSAEncryption", "SHA384 with RSA signature"),
("sha512WithRSAEncryption", "SHA512 with RSA signature"),
("ecdsa-with-SHA256", "SHA256 with ECDSA signature"),
("ecdsa-with-SHA384", "SHA384 with ECDSA signature"),
("ecdsa-with-SHA512", "SHA512 with ECDSA signature"),
("dsaWithSHA1", "SHA1 with DSA signature"),
("dsaWithSHA256", "SHA256 with DSA signature"),
(
"Ed25519",
"Edwards-Curve Digital Signature Algorithm with 25519 curve",
),
("Ed448", "Edwards-Curve Digital Signature with 448 curve"),
],
default=django_x509.base.models.default_digest_algorithm,
help_text="The digest algorithm to use for computing the digest. This is a combination of a hashing algorithm and a signature algorithm. For Edwards-Curves, the hashing algorithm is already baked into the signature.",
max_length=23,
verbose_name="digest algorithm",
),
),
migrations.AlterField(
model_name="ca",
name="extensions",
field=jsonfield.fields.JSONField(
blank=True,
default=list,
dump_kwargs={"indent": 4},
help_text="Additional x509 certificate extensions",
load_kwargs={"object_pairs_hook": collections.OrderedDict},
verbose_name="extensions",
),
),
migrations.AlterField(
model_name="ca",
name="key_length",
field=models.CharField(
blank=True,
choices=[
(None, "---"),
("512", "512"),
("1024", "1024"),
("2048", "2048"),
("4096", "4096"),
],
default=django_x509.base.models.default_key_length,
help_text="bits",
max_length=6,
null=True,
verbose_name="key length",
),
),
migrations.AlterField(
model_name="ca",
name="private_key",
field=models.TextField(
blank=True, help_text="Private key in X.509 PEM format"
),
),
migrations.AlterField(
model_name="ca",
name="serial_number",
field=models.CharField(
blank=True,
help_text="Leave blank to determine automatically",
max_length=48,
null=True,
verbose_name="serial number",
),
),
migrations.AlterField(
model_name="cert",
name="certificate",
field=models.TextField(
blank=True, help_text="Certificate in X.509 PEM format"
),
),
migrations.AlterField(
model_name="cert",
name="digest",
field=models.CharField(
choices=[
("sha1WithRSAEncryption", "SHA1 with RSA signature"),
("sha224WithRSAEncryption", "SHA224 with RSA signature"),
("sha256WithRSAEncryption", "SHA256 with RSA signature"),
("sha384WithRSAEncryption", "SHA384 with RSA signature"),
("sha512WithRSAEncryption", "SHA512 with RSA signature"),
("ecdsa-with-SHA256", "SHA256 with ECDSA signature"),
("ecdsa-with-SHA384", "SHA384 with ECDSA signature"),
("ecdsa-with-SHA512", "SHA512 with ECDSA signature"),
("dsaWithSHA1", "SHA1 with DSA signature"),
("dsaWithSHA256", "SHA256 with DSA signature"),
(
"Ed25519",
"Edwards-Curve Digital Signature Algorithm with 25519 curve",
),
("Ed448", "Edwards-Curve Digital Signature with 448 curve"),
],
default=django_x509.base.models.default_digest_algorithm,
help_text="The digest algorithm to use for computing the digest. This is a combination of a hashing algorithm and a signature algorithm. For Edwards-Curves, the hashing algorithm is already baked into the signature.",
max_length=23,
verbose_name="digest algorithm",
),
),
migrations.AlterField(
model_name="cert",
name="extensions",
field=jsonfield.fields.JSONField(
blank=True,
default=list,
dump_kwargs={"indent": 4},
help_text="Additional x509 certificate extensions",
load_kwargs={"object_pairs_hook": collections.OrderedDict},
verbose_name="extensions",
),
),
migrations.AlterField(
model_name="cert",
name="key_length",
field=models.CharField(
blank=True,
choices=[
(None, "---"),
("512", "512"),
("1024", "1024"),
("2048", "2048"),
("4096", "4096"),
],
default=django_x509.base.models.default_key_length,
help_text="bits",
max_length=6,
null=True,
verbose_name="key length",
),
),
migrations.AlterField(
model_name="cert",
name="private_key",
field=models.TextField(
blank=True, help_text="Private key in X.509 PEM format"
),
),
migrations.AlterField(
model_name="cert",
name="serial_number",
field=models.CharField(
blank=True,
help_text="Leave blank to determine automatically",
max_length=48,
null=True,
verbose_name="serial number",
),
),
]
51 changes: 51 additions & 0 deletions django_x509/migrations/0011_auto_20251006_1025.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Generated by Django 5.2.7 on 2025-10-06 08:25

from django.db import migrations


def alter_choices_certificates(apps, schema_editor):
"""Alter old digest choices to new digest choices (also mentioning the encryption algorithm)."""
Ca = apps.get_model("django_x509", "Ca")
Ca.objects.filter(digest="sha1").update(digest="sha1WithRSAEncryption")
Ca.objects.filter(digest="sha224").update(digest="sha224WithRSAEncryption")
Ca.objects.filter(digest="sha256").update(digest="sha256WithRSAEncryption")
Ca.objects.filter(digest="sha384").update(digest="sha384WithRSAEncryption")
Ca.objects.filter(digest="sha512").update(digest="sha512WithRSAEncryption")

Cert = apps.get_model("django_x509", "Cert")
Cert.objects.filter(digest="sha1").update(digest="sha1WithRSAEncryption")
Cert.objects.filter(digest="sha224").update(digest="sha224WithRSAEncryption")
Cert.objects.filter(digest="sha256").update(digest="sha256WithRSAEncryption")
Cert.objects.filter(digest="sha384").update(digest="sha384WithRSAEncryption")
Cert.objects.filter(digest="sha512").update(digest="sha512WithRSAEncryption")


def alter_choices_certificate_reverse(apps, schema_editor):
"""Reverse the operations of alter_choices_certificates."""
Ca = apps.get_model("django_x509", "Ca")
Ca.objects.filter(digest="sha1WithRSAEncryption").update(digest="sha1")
Ca.objects.filter(digest="sha224WithRSAEncryption").update(digest="sha224")
Ca.objects.filter(digest="sha256WithRSAEncryption").update(digest="sha256")
Ca.objects.filter(digest="sha384WithRSAEncryption").update(digest="sha384")
Ca.objects.filter(digest="sha512WithRSAEncryption").update(digest="sha512")

Cert = apps.get_model("django_x509", "Cert")
Cert.objects.filter(digest="sha1WithRSAEncryption").update(digest="sha1")
Cert.objects.filter(digest="sha224WithRSAEncryption").update(digest="sha224")
Cert.objects.filter(digest="sha256WithRSAEncryption").update(digest="sha256")
Cert.objects.filter(digest="sha384WithRSAEncryption").update(digest="sha384")
Cert.objects.filter(digest="sha512WithRSAEncryption").update(digest="sha512")


class Migration(migrations.Migration):

dependencies = [
("django_x509", "0010_alter_ca_certificate_alter_ca_digest_and_more"),
]

operations = [
migrations.RunPython(
alter_choices_certificates,
reverse_code=alter_choices_certificate_reverse
)
]
64 changes: 64 additions & 0 deletions django_x509/migrations/0012_alter_ca_digest_alter_cert_digest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Generated by Django 5.2.7 on 2025-10-06 08:26

import django_x509.base.models
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("django_x509", "0011_auto_20251006_1025"),
]

operations = [
migrations.AlterField(
model_name="ca",
name="digest",
field=models.CharField(
choices=[
("sha224WithRSAEncryption", "SHA224 with RSA signature"),
("sha256WithRSAEncryption", "SHA256 with RSA signature"),
("sha384WithRSAEncryption", "SHA384 with RSA signature"),
("sha512WithRSAEncryption", "SHA512 with RSA signature"),
("ecdsa-with-SHA256", "SHA256 with ECDSA signature"),
("ecdsa-with-SHA384", "SHA384 with ECDSA signature"),
("ecdsa-with-SHA512", "SHA512 with ECDSA signature"),
("dsaWithSHA256", "SHA256 with DSA signature"),
(
"Ed25519",
"Edwards-Curve Digital Signature Algorithm with 25519 curve",
),
("Ed448", "Edwards-Curve Digital Signature with 448 curve"),
],
default=django_x509.base.models.default_digest_algorithm,
help_text="The digest algorithm to use for computing the digest. This is a combination of a hashing algorithm and a signature algorithm. For Edwards-Curves, the hashing algorithm is already baked into the signature.",
max_length=23,
verbose_name="digest algorithm",
),
),
migrations.AlterField(
model_name="cert",
name="digest",
field=models.CharField(
choices=[
("sha224WithRSAEncryption", "SHA224 with RSA signature"),
("sha256WithRSAEncryption", "SHA256 with RSA signature"),
("sha384WithRSAEncryption", "SHA384 with RSA signature"),
("sha512WithRSAEncryption", "SHA512 with RSA signature"),
("ecdsa-with-SHA256", "SHA256 with ECDSA signature"),
("ecdsa-with-SHA384", "SHA384 with ECDSA signature"),
("ecdsa-with-SHA512", "SHA512 with ECDSA signature"),
("dsaWithSHA256", "SHA256 with DSA signature"),
(
"Ed25519",
"Edwards-Curve Digital Signature Algorithm with 25519 curve",
),
("Ed448", "Edwards-Curve Digital Signature with 448 curve"),
],
default=django_x509.base.models.default_digest_algorithm,
help_text="The digest algorithm to use for computing the digest. This is a combination of a hashing algorithm and a signature algorithm. For Edwards-Curves, the hashing algorithm is already baked into the signature.",
max_length=23,
verbose_name="digest algorithm",
),
),
]
26 changes: 23 additions & 3 deletions django_x509/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
DEFAULT_CA_VALIDITY = getattr(settings, "DJANGO_X509_DEFAULT_CA_VALIDITY", 3650)
DEFAULT_KEY_LENGTH = str(getattr(settings, "DJANGO_X509_DEFAULT_KEY_LENGTH", "2048"))
DEFAULT_DIGEST_ALGORITHM = getattr(
settings, "DJANGO_X509_DEFAULT_DIGEST_ALGORITHM", "sha256"
settings, "DJANGO_X509_DEFAULT_DIGEST_ALGORITHM", "sha256WithRSAEncryption"
)
CA_BASIC_CONSTRAINTS_CRITICAL = getattr(
settings, "DJANGO_X509_CA_BASIC_CONSTRAINTS_CRITICAL", True
Expand All @@ -14,10 +14,30 @@
)
CA_KEYUSAGE_CRITICAL = getattr(settings, "DJANGO_X509_CA_KEYUSAGE_CRITICAL", True)
CA_KEYUSAGE_VALUE = getattr(
settings, "DJANGO_X509_CA_KEYUSAGE_VALUE", "cRLSign, keyCertSign"
settings, "DJANGO_X509_CA_KEYUSAGE_VALUE", {
"digital_signature": False,
"content_commitment": False,
"key_encipherment": False,
"data_encipherment": False,
"key_agreement": False,
"key_cert_sign": True,
"crl_sign": True,
"encipher_only": False,
"decipher_only": False,
}
)
CERT_KEYUSAGE_CRITICAL = getattr(settings, "DJANGO_X509_CERT_KEYUSAGE_CRITICAL", False)
CERT_KEYUSAGE_VALUE = getattr(
settings, "DJANGO_X509_CERT_KEYUSAGE_VALUE", "digitalSignature, keyEncipherment"
settings, "DJANGO_X509_CERT_KEYUSAGE_VALUE", {
"digital_signature": True,
"content_commitment": False,
"key_encipherment": True,
"data_encipherment": False,
"key_agreement": False,
"key_cert_sign": False,
"crl_sign": False,
"encipher_only": False,
"decipher_only": False,
}
) # noqa
CRL_PROTECTED = getattr(settings, "DJANGO_X509_CRL_PROTECTED", False)
12 changes: 7 additions & 5 deletions django_x509/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,12 @@ def get_message_strings(self):


class TestX509Mixin(object):
def _create_ca(self, **kwargs):
@staticmethod
def _create_ca(**kwargs):
options = dict(
name="Test CA",
key_length="2048",
digest="sha256",
digest="sha256WithRSAEncryption",
country_code="IT",
state="RM",
city="Rome",
Expand All @@ -40,14 +41,15 @@ def _create_ca(self, **kwargs):
ca.save()
return ca

def _create_cert(self, cert_model=None, **kwargs):
@staticmethod
def _create_cert(cert_model=None, **kwargs):
if not cert_model:
cert_model = Cert
options = dict(
name="TestCert",
ca=None,
key_length="2048",
digest="sha256",
digest="sha256WithRSAEncryption",
country_code="IT",
state="RM",
city="Rome",
Expand All @@ -59,7 +61,7 @@ def _create_cert(self, cert_model=None, **kwargs):
options.update(kwargs)
# auto create CA if not supplied
if not options.get("ca"):
options["ca"] = self._create_ca()
options["ca"] = TestX509Mixin._create_ca()
cert = cert_model(**options)
cert.full_clean()
cert.save()
Expand Down
Loading
Loading