mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
parameters: introduce CertificateSigningRequest
Previously, CSRs were handled as a Str parameter which brought trouble to Python 3 because of its more strict type requirements. We introduce a CertificateSigningRequest parameter which allows to use python-cryptography x509.CertificateSigningRequest to represent CSRs in the framework. https://pagure.io/freeipa/issue/7131
This commit is contained in:
@@ -115,12 +115,15 @@ from ipalib.base import check_name
|
||||
from ipalib.plugable import ReadOnly, lock
|
||||
from ipalib.errors import ConversionError, RequirementError, ValidationError
|
||||
from ipalib.errors import (
|
||||
PasswordMismatch, Base64DecodeError, CertificateFormatError
|
||||
PasswordMismatch, Base64DecodeError, CertificateFormatError,
|
||||
CertificateOperationError
|
||||
)
|
||||
from ipalib.constants import TYPE_ERROR, CALLABLE_ERROR, LDAP_GENERALIZED_TIME_FORMAT
|
||||
from ipalib.text import Gettext, FixMe
|
||||
from ipalib.util import json_serialize, validate_idna_domain
|
||||
from ipalib.x509 import load_der_x509_certificate, IPACertificate
|
||||
from ipalib.x509 import (
|
||||
load_der_x509_certificate, IPACertificate, default_backend)
|
||||
from ipalib.pkcs10 import strip_header as strip_csr_header
|
||||
from ipapython import kerberos
|
||||
from ipapython.dn import DN
|
||||
from ipapython.dnsutil import DNSName
|
||||
@@ -1452,6 +1455,60 @@ class Certificate(Param):
|
||||
return super(Certificate, self)._convert_scalar(value)
|
||||
|
||||
|
||||
class CertificateSigningRequest(Param):
|
||||
type = crypto_x509.CertificateSigningRequest
|
||||
type_error = _('must be a certificate signing request')
|
||||
allowed_types = (crypto_x509.CertificateSigningRequest, bytes, unicode)
|
||||
|
||||
def __extract_der_from_input(self, value):
|
||||
"""
|
||||
Tries to get the DER representation of whatever we receive as an input
|
||||
|
||||
:param value:
|
||||
bytes instance containing something we hope is a certificate
|
||||
signing request
|
||||
:returns:
|
||||
base64-decoded representation of whatever we found in case input
|
||||
had been something else than DER or something which resembles
|
||||
DER, in which case we would just return input
|
||||
"""
|
||||
try:
|
||||
value.decode('utf-8')
|
||||
except UnicodeDecodeError:
|
||||
# possibly DER-encoded CSR or something similar
|
||||
return value
|
||||
|
||||
value = strip_csr_header(value)
|
||||
return base64.b64decode(value)
|
||||
|
||||
def _convert_scalar(self, value, index=None):
|
||||
"""
|
||||
:param value:
|
||||
either DER csr, base64-encoded csr or an object implementing the
|
||||
cryptography.CertificateSigningRequest interface
|
||||
:returns:
|
||||
an object with the cryptography.CertificateSigningRequest interface
|
||||
"""
|
||||
if isinstance(value, unicode):
|
||||
try:
|
||||
value = value.encode('ascii')
|
||||
except UnicodeDecodeError:
|
||||
raise CertificateOperationError('not a valid CSR')
|
||||
|
||||
if isinstance(value, bytes):
|
||||
# try to extract DER from whatever we got
|
||||
value = self.__extract_der_from_input(value)
|
||||
try:
|
||||
value = crypto_x509.load_der_x509_csr(
|
||||
value, backend=default_backend())
|
||||
except ValueError as e:
|
||||
raise CertificateOperationError(
|
||||
error=_("Failure decoding Certificate Signing Request:"
|
||||
" %s") % e)
|
||||
|
||||
return super(CertificateSigningRequest, self)._convert_scalar(value)
|
||||
|
||||
|
||||
class Str(Data):
|
||||
"""
|
||||
A parameter for Unicode text (stored in the ``unicode`` type).
|
||||
|
||||
@@ -29,13 +29,13 @@ def strip_header(csr):
|
||||
Remove the header and footer (and surrounding material) from a CSR.
|
||||
"""
|
||||
headerlen = 40
|
||||
s = csr.find("-----BEGIN NEW CERTIFICATE REQUEST-----")
|
||||
s = csr.find(b"-----BEGIN NEW CERTIFICATE REQUEST-----")
|
||||
if s == -1:
|
||||
headerlen = 36
|
||||
s = csr.find("-----BEGIN CERTIFICATE REQUEST-----")
|
||||
s = csr.find(b"-----BEGIN CERTIFICATE REQUEST-----")
|
||||
if s >= 0:
|
||||
e = csr.find("-----END")
|
||||
csr = csr[s+headerlen:e]
|
||||
e = csr.find(b"-----END")
|
||||
csr = csr[s + headerlen:e]
|
||||
|
||||
return csr
|
||||
|
||||
|
||||
@@ -197,6 +197,10 @@ def xml_wrap(value, version):
|
||||
return base64.b64encode(
|
||||
value.public_bytes(x509_Encoding.DER)).decode('ascii')
|
||||
|
||||
if isinstance(value, crypto_x509.CertificateSigningRequest):
|
||||
return base64.b64encode(
|
||||
value.public_bytes(x509_Encoding.DER)).decode('ascii')
|
||||
|
||||
assert type(value) in (unicode, float, bool, type(None)) + six.integer_types
|
||||
return value
|
||||
|
||||
@@ -325,6 +329,7 @@ class _JSONPrimer(dict):
|
||||
tuple: self._enc_list,
|
||||
dict: self._enc_dict,
|
||||
crypto_x509.Certificate: self._enc_certificate,
|
||||
crypto_x509.CertificateSigningRequest: self._enc_certificate,
|
||||
})
|
||||
# int, long
|
||||
for t in six.integer_types:
|
||||
|
||||
Reference in New Issue
Block a user