Repository: goauthentik/authentik
File: authentik/enterprise/license.py (Python)

Code before:
    @staticmethod
    def validate(jwt: str, check_expiry=True) -> LicenseKey:
        """Validate the license from a given JWT"""
        try:
            headers = get_unverified_header(jwt)
        except PyJWTError:
            raise ValidationError("Unable to verify license") from None
        x5c: list[str] = headers.get("x5c", [])
        if len(x5c) < 1:
            raise ValidationError("Unable to verify license")
        try:
            our_cert = load_der_x509_certificate(b64decode(x5c[0]))
            intermediate = load_der_x509_certificate(b64decode(x5c[1]))
            our_cert.verify_directly_issued_by(intermediate)
            intermediate.verify_directly_issued_by(get_licensing_key())
        except InvalidSignature, TypeError, ValueError, Error:
            raise ValidationError("Unable to verify license") from None
        try:
            ECAlgorithm._validate_curve = lambda *_: True
            body = from_dict(
                LicenseKey,
                decode(
                    jwt,
                    our_cert.public_key(),
                    algorithms=["ES512"],
                    audience=get_license_aud(),
                    options={"verify_exp": check_expiry, "verify_signature": check_expiry},
                ),
            )
        except PyJWTError:
            unverified = decode(jwt, options={"verify_signature": False})
            if unverified["aud"] != get_license_aud():
                raise ValidationError("Invalid Install ID in license") from None
            raise ValidationError("Unable to verify license") from None
        return body

    @staticmethod
    def get_total() -> LicenseKey:
        """Get a summarized version of all (not expired) licenses"""
        total = LicenseKey(get_license_aud(), 0, "Summarized license", 0, 0)
        for lic in License.objects.all():
            if lic.is_valid:
                total.internal_users += lic.internal_users
                total.external_users += lic.external_users
                total.license_flags.extend(lic.status.license_flags)
            exp_ts = int(mktime(lic.expiry.timetuple()))
            if total.exp == 0:
                total.exp = exp_ts
            total.exp = max(total.exp, exp_ts)
        return total


Review comment (security):
```suggestion
            # See https://github.com/goauthentik/authentik/pull/20402
            ECAlgorithm._validate_curve = lambda *_: True
```

Code after:
    @staticmethod
    def validate(jwt: str, check_expiry=True) -> LicenseKey:
        """Validate the license from a given JWT"""
        try:
            headers = get_unverified_header(jwt)
        except PyJWTError:
            raise ValidationError("Unable to verify license") from None
        x5c: list[str] = headers.get("x5c", [])
        if len(x5c) < 1:
            raise ValidationError("Unable to verify license")
        try:
            our_cert = load_der_x509_certificate(b64decode(x5c[0]))
            intermediate = load_der_x509_certificate(b64decode(x5c[1]))
            our_cert.verify_directly_issued_by(intermediate)
            intermediate.verify_directly_issued_by(get_licensing_key())
        except InvalidSignature, TypeError, ValueError, Error:
            raise ValidationError("Unable to verify license") from None
        _validate_curve_original = ECAlgorithm._validate_curve
        try:
            # authentik's license used to be generated with `algorithm="ES512"` and signed with
            # a key of curve `secp384r1`. Starting with version 2.11.0, pyjwt enforces the spec, see
            # https://github.com/jpadilla/pyjwt/commit/5b8622773358e56d3d3c0a9acf404809ff34433a
            # New licenses are generated with `algorithm="ES384"` and signed with `secp384r1`.
            # The last license will run out by March 2027.
            # TODO: remove this in March 2027.
            ECAlgorithm._validate_curve = lambda *_: True
            body = from_dict(
                LicenseKey,
                decode(
                    jwt,
                    our_cert.public_key(),
                    algorithms=["ES512"],
                    audience=get_license_aud(),
                    options={"verify_exp": check_expiry, "verify_signature": check_expiry},
                ),
            )
        except PyJWTError:
            unverified = decode(jwt, options={"verify_signature": False})
            if unverified["aud"] != get_license_aud():
                raise ValidationError("Invalid Install ID in license") from None
            raise ValidationError("Unable to verify license") from None
        finally:
            ECAlgorithm._validate_curve = _validate_curve_original
        return body

    @staticmethod
    def get_total() -> LicenseKey:
        """Get a summarized version of all (not expired) licenses"""
        total = LicenseKey(get_license_aud(), 0, "Summarized license", 0, 0)
        for lic in License.objects.all():
            if lic.is_valid: