From c1f0833c09cc266fbce9b8a35e52a92cd98dd582 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Wed, 22 Dec 2021 21:46:22 +0100 Subject: [PATCH] crypto: improve support for non-rsa private keys (discovery) Signed-off-by: Jens Langhammer --- authentik/crypto/api.py | 2 +- authentik/crypto/models.py | 13 +++++++++---- authentik/crypto/tasks.py | 4 ++-- website/docs/core/certificates.md | 2 +- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/authentik/crypto/api.py b/authentik/crypto/api.py index 08bbf86f8..6f14fc115 100644 --- a/authentik/crypto/api.py +++ b/authentik/crypto/api.py @@ -72,7 +72,7 @@ class CertificateKeyPairSerializer(ModelSerializer): return value def validate_key_data(self, value: str) -> str: - """Verify that input is a valid PEM RSA Key""" + """Verify that input is a valid PEM Key""" # Since this field is optional, data can be empty. if value != "": try: diff --git a/authentik/crypto/models.py b/authentik/crypto/models.py index 037e8dffd..972e8d6cc 100644 --- a/authentik/crypto/models.py +++ b/authentik/crypto/models.py @@ -6,6 +6,11 @@ from uuid import uuid4 from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric.ec import ( + EllipticCurvePrivateKey, + EllipticCurvePublicKey, +) +from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey, Ed25519PublicKey from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey, RSAPublicKey from cryptography.hazmat.primitives.serialization import load_pem_private_key from cryptography.x509 import Certificate, load_pem_x509_certificate @@ -36,8 +41,8 @@ class CertificateKeyPair(ManagedModel, CreatedUpdatedModel): ) _cert: Optional[Certificate] = None - _private_key: Optional[RSAPrivateKey] = None - _public_key: Optional[RSAPublicKey] = None + _private_key: Optional[RSAPrivateKey | EllipticCurvePrivateKey | Ed25519PrivateKey] = None + _public_key: Optional[RSAPublicKey | EllipticCurvePublicKey | Ed25519PublicKey] = None @property def certificate(self) -> Certificate: @@ -49,14 +54,14 @@ class CertificateKeyPair(ManagedModel, CreatedUpdatedModel): return self._cert @property - def public_key(self) -> Optional[RSAPublicKey]: + def public_key(self) -> Optional[RSAPublicKey | EllipticCurvePublicKey]: """Get public key of the private key""" if not self._public_key: self._public_key = self.private_key.public_key() return self._public_key @property - def private_key(self) -> Optional[RSAPrivateKey]: + def private_key(self) -> Optional[RSAPrivateKey | EllipticCurvePrivateKey]: """Get python cryptography PrivateKey instance""" if not self._private_key and self.key_data != "": try: diff --git a/authentik/crypto/tasks.py b/authentik/crypto/tasks.py index df1f28bea..cd6a3afaf 100644 --- a/authentik/crypto/tasks.py +++ b/authentik/crypto/tasks.py @@ -24,7 +24,7 @@ MANAGED_DISCOVERED = "goauthentik.io/crypto/discovered/%s" def ensure_private_key_valid(body: str): - """Attempt loading of an RSA Private key without password""" + """Attempt loading of a PEM Private key without password""" load_pem_private_key( str.encode("\n".join([x.strip() for x in body.split("\n")])), password=None, @@ -60,7 +60,7 @@ def certificate_discovery(self: MonitoredTask): try: with open(path, "r+", encoding="utf-8") as _file: body = _file.read() - if "BEGIN RSA PRIVATE KEY" in body: + if "PRIVATE KEY" in body: private_keys[cert_name] = ensure_private_key_valid(body) else: certs[cert_name] = ensure_certificate_valid(body) diff --git a/website/docs/core/certificates.md b/website/docs/core/certificates.md index c8c87024c..056946f46 100644 --- a/website/docs/core/certificates.md +++ b/website/docs/core/certificates.md @@ -34,7 +34,7 @@ You can also bind mount single files into the folder, as long as they fall under `/foo.pem` Will be imported as the keypair `foo`. Based on its content its either imported as certificate or private key. - Currently, only RSA Keys are supported, so if the file contains `BEGIN RSA PRIVATE KEY` it will imported as private key. + Files containing `PRIVATE KEY` it will imported as private key. Otherwise it will be imported as certificate.