providers/saml: switch to new crypto

This commit is contained in:
Jens Langhammer 2020-03-03 23:35:50 +01:00
parent dc8b89a6b9
commit 80a50f9bdb
7 changed files with 47 additions and 106 deletions

View File

@ -24,9 +24,7 @@ class SAMLProviderSerializer(ModelSerializer):
"property_mappings",
"digest_algorithm",
"signature_algorithm",
"signing",
"signing_cert",
"signing_key",
"singing_kp",
]

View File

@ -9,7 +9,6 @@ from passbook.providers.saml.models import (
SAMLProvider,
get_provider_choices,
)
from passbook.providers.saml.utils.cert import CertificateBuilder
class SAMLProviderForm(forms.ModelForm):
@ -19,13 +18,6 @@ class SAMLProviderForm(forms.ModelForm):
choices=get_provider_choices(), label="Processor"
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
builder = CertificateBuilder()
builder.build()
self.fields["signing_cert"].initial = builder.certificate
self.fields["signing_key"].initial = builder.private_key
class Meta:
model = SAMLProvider
@ -41,9 +33,7 @@ class SAMLProviderForm(forms.ModelForm):
"property_mappings",
"digest_algorithm",
"signature_algorithm",
"signing",
"signing_cert",
"signing_key",
"singing_kp",
]
widgets = {
"name": forms.TextInput(),

View File

@ -0,0 +1,29 @@
# Generated by Django 3.0.3 on 2020-03-03 21:57
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("passbook_crypto", "0001_initial"),
("passbook_providers_saml", "0006_auto_20200217_2031"),
]
operations = [
migrations.RemoveField(model_name="samlprovider", name="signing",),
migrations.RemoveField(model_name="samlprovider", name="signing_cert",),
migrations.RemoveField(model_name="samlprovider", name="signing_key",),
migrations.AddField(
model_name="samlprovider",
name="singing_kp",
field=models.ForeignKey(
default=None,
help_text="Singing is enabled upon selection of a Key Pair.",
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="passbook_crypto.CertificateKeyPair",
),
),
]

View File

@ -8,6 +8,7 @@ from django.utils.translation import ugettext_lazy as _
from structlog import get_logger
from passbook.core.models import PropertyMapping, Provider
from passbook.crypto.models import CertificateKeyPair
from passbook.lib.utils.reflection import class_to_path, path_to_class
from passbook.lib.utils.template import render_to_string
from passbook.providers.saml.processors.base import Processor
@ -74,9 +75,13 @@ class SAMLProvider(Provider):
default="rsa-sha256",
)
signing = models.BooleanField(default=True)
signing_cert = models.TextField(verbose_name=_("Singing Certificate"))
signing_key = models.TextField()
singing_kp = models.ForeignKey(
CertificateKeyPair,
default=None,
null=True,
help_text=_("Singing is enabled upon selection of a Key Pair."),
on_delete=models.SET_NULL,
)
form = "passbook.providers.saml.forms.SAMLProviderForm"
_processor = None

View File

@ -1,84 +0,0 @@
"""Create self-signed certificates"""
import datetime
import uuid
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.x509.oid import NameOID
class CertificateBuilder:
"""Build self-signed certificates"""
__public_key = None
__private_key = None
__builder = None
__certificate = None
def __init__(self):
self.__public_key = None
self.__private_key = None
self.__builder = None
self.__certificate = None
def build(self):
"""Build self-signed certificate"""
one_day = datetime.timedelta(1, 0, 0)
self.__private_key = rsa.generate_private_key(
public_exponent=65537, key_size=2048, backend=default_backend()
)
self.__public_key = self.__private_key.public_key()
self.__builder = (
x509.CertificateBuilder()
.subject_name(
x509.Name(
[
x509.NameAttribute(
NameOID.COMMON_NAME,
u"passbook Self-signed SAML Certificate",
),
x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"passbook"),
x509.NameAttribute(
NameOID.ORGANIZATIONAL_UNIT_NAME, u"Self-signed"
),
]
)
)
.issuer_name(
x509.Name(
[
x509.NameAttribute(
NameOID.COMMON_NAME,
u"passbook Self-signed SAML Certificate",
),
]
)
)
.not_valid_before(datetime.datetime.today() - one_day)
.not_valid_after(datetime.datetime.today() + datetime.timedelta(days=365))
.serial_number(int(uuid.uuid4()))
.public_key(self.__public_key)
)
self.__certificate = self.__builder.sign(
private_key=self.__private_key,
algorithm=hashes.SHA256(),
backend=default_backend(),
)
@property
def private_key(self):
"""Return private key in PEM format"""
return self.__private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption(),
).decode("utf-8")
@property
def certificate(self):
"""Return certificate in PEM format"""
return self.__certificate.public_bytes(
encoding=serialization.Encoding.PEM,
).decode("utf-8")

View File

@ -31,9 +31,12 @@ def sign_with_signxml(data: str, provider: "SAMLProvider", reference_uri=None) -
digest_algorithm=provider.digest_algorithm,
)
signed = signer.sign(
root, key=key, cert=[provider.signing_cert], reference_uri=reference_uri
root,
key=key,
cert=[provider.singing_kp.certificate_data],
reference_uri=reference_uri,
)
XMLVerifier().verify(signed, x509_cert=provider.signing_cert)
XMLVerifier().verify(signed, x509_cert=provider.singing_kp.certificate_data)
return etree.tostring(signed).decode("utf-8") # nosec

View File

@ -274,9 +274,9 @@ class DescriptorDownloadView(AccessRequiredView):
kwargs={"application": provider.application.slug},
)
)
pubkey = strip_pem_header(provider.signing_cert.replace("\r", "")).replace(
"\n", ""
)
pubkey = strip_pem_header(
provider.singing_kp.certificate_data.replace("\r", "")
).replace("\n", "")
subject_format = provider.processor.subject_format
ctx = {
"entity_id": entity_id,