crypto: fully parse certificate on validation in serializer to prevent invalid certificates from being saved

closes #2082

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer 2022-01-10 20:36:50 +01:00
parent 4817126811
commit 11e25617bd
1 changed files with 18 additions and 7 deletions

View File

@ -17,6 +17,7 @@ from rest_framework.request import Request
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.serializers import ModelSerializer, ValidationError from rest_framework.serializers import ModelSerializer, ValidationError
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from structlog.stdlib import get_logger
from authentik.api.decorators import permission_required from authentik.api.decorators import permission_required
from authentik.core.api.used_by import UsedByMixin from authentik.core.api.used_by import UsedByMixin
@ -26,6 +27,8 @@ from authentik.crypto.managed import MANAGED_KEY
from authentik.crypto.models import CertificateKeyPair from authentik.crypto.models import CertificateKeyPair
from authentik.events.models import Event, EventAction from authentik.events.models import Event, EventAction
LOGGER = get_logger()
class CertificateKeyPairSerializer(ModelSerializer): class CertificateKeyPairSerializer(ModelSerializer):
"""CertificateKeyPair Serializer""" """CertificateKeyPair Serializer"""
@ -76,8 +79,11 @@ class CertificateKeyPairSerializer(ModelSerializer):
def validate_certificate_data(self, value: str) -> str: def validate_certificate_data(self, value: str) -> str:
"""Verify that input is a valid PEM x509 Certificate""" """Verify that input is a valid PEM x509 Certificate"""
try: try:
load_pem_x509_certificate(value.encode("utf-8"), default_backend()) # Cast to string to fully load and parse certificate
except ValueError: # Prevents issues like https://github.com/goauthentik/authentik/issues/2082
str(load_pem_x509_certificate(value.encode("utf-8"), default_backend()))
except ValueError as exc:
LOGGER.warning("Failed to load certificate", exc=exc)
raise ValidationError("Unable to load certificate.") raise ValidationError("Unable to load certificate.")
return value return value
@ -86,12 +92,17 @@ class CertificateKeyPairSerializer(ModelSerializer):
# Since this field is optional, data can be empty. # Since this field is optional, data can be empty.
if value != "": if value != "":
try: try:
load_pem_private_key( # Cast to string to fully load and parse certificate
str.encode("\n".join([x.strip() for x in value.split("\n")])), # Prevents issues like https://github.com/goauthentik/authentik/issues/2082
password=None, str(
backend=default_backend(), load_pem_private_key(
str.encode("\n".join([x.strip() for x in value.split("\n")])),
password=None,
backend=default_backend(),
)
) )
except (ValueError, TypeError): except (ValueError, TypeError) as exc:
LOGGER.warning("Failed to load private key", exc=exc)
raise ValidationError("Unable to load private key (possibly encrypted?).") raise ValidationError("Unable to load private key (possibly encrypted?).")
return value return value