URL: https://github.com/freeipa/freeipa/pull/1110
Author: stlaz
 Title: #1110: csrgen: Introduce CertificateSigningRequest parameter
Action: opened

PR body:
"""
This pull request tries to introduce a new parameter for CSRs so that these are 
handled properly in Python 3 and are backward-compatible with the older API 
which will try to send strings to the server.

**NOTE**: tests for the new parameter are currently not included, it's here for 
the sole purpose of a review of the code and should not be pushed until the 
tests arrive.

- [x] do the code
- [ ] do the tests

-----------------------
This PR includes code @flo-renaud's fix from 
https://github.com/freeipa/freeipa/pull/1057
"""

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/1110/head:pr1110
git checkout pr1110
From 6ce1d9db943327e2a41d91841537802d4381be76 Mon Sep 17 00:00:00 2001
From: Florence Blanc-Renaud <f...@redhat.com>
Date: Mon, 11 Sep 2017 18:24:22 +0200
Subject: [PATCH 1/7] py3: fix ipa cert-request --database ...

Fix bytes vs str issues in ipa cert-request

https://pagure.io/freeipa/issue/7148
---
 ipaclient/csrgen.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/ipaclient/csrgen.py b/ipaclient/csrgen.py
index 3f3ea1cde6..a22ccfb161 100644
--- a/ipaclient/csrgen.py
+++ b/ipaclient/csrgen.py
@@ -407,11 +407,11 @@ def __init__(self, key_filename, password_filename):
         self.password_filename = password_filename
 
     def key(self):
-        with open(self.key_filename, 'r') as key_file:
+        with open(self.key_filename, 'rb') as key_file:
             key_bytes = key_file.read()
         password = None
         if self.password_filename is not None:
-            with open(self.password_filename, 'r') as password_file:
+            with open(self.password_filename, 'rb') as password_file:
                 password = password_file.read().strip()
 
         key = load_pem_private_key(key_bytes, password, default_backend())

From ca3a33e41681016620b84ebec1fbe90806238434 Mon Sep 17 00:00:00 2001
From: Stanislav Laznicka <slazn...@redhat.com>
Date: Wed, 20 Sep 2017 10:50:24 +0200
Subject: [PATCH 2/7] csrgen_ffi: pass bytes where "char *" is required

In Python 3, "char *" corresponds to bytes rather than string.

https://pagure.io/freeipa/issue/7131
---
 ipaclient/csrgen_ffi.py | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/ipaclient/csrgen_ffi.py b/ipaclient/csrgen_ffi.py
index 2d9b782945..0c9a54b561 100644
--- a/ipaclient/csrgen_ffi.py
+++ b/ipaclient/csrgen_ffi.py
@@ -196,11 +196,11 @@ def _parse_dn_section(subj, dn_sk):
 
         # Skip past any leading X. X: X, etc to allow for multiple instances
         for idx, c in enumerate(rdn_type):
-            if c in ':,.':
+            if c in b':,.':
                 if idx+1 < len(rdn_type):
                     rdn_type = rdn_type[idx+1:]
                 break
-        if rdn_type.startswith('+'):
+        if rdn_type.startswith(b'+'):
             rdn_type = rdn_type[1:]
             mval = -1
         else:
@@ -236,7 +236,7 @@ def build_requestinfo(config, public_key_info):
                 raise errors.CSRTemplateError(
                     reason='Error on line %d of config file' % errorline[0])
 
-        dn_sect = NCONF_get_string(reqdata, 'req', 'distinguished_name')
+        dn_sect = NCONF_get_string(reqdata, b'req', b'distinguished_name')
         if dn_sect == NULL:
             raise errors.CSRTemplateError(
                 reason='Unable to find "distinguished_name" key in config')
@@ -267,7 +267,7 @@ def build_requestinfo(config, public_key_info):
         X509V3_set_ctx(ext_ctx, NULL, NULL, req, NULL, 0)
         X509V3_set_nconf(ext_ctx, reqdata)
 
-        extn_section = NCONF_get_string(reqdata, "req", "req_extensions")
+        extn_section = NCONF_get_string(reqdata, b"req", b"req_extensions")
         if extn_section != NULL:
             if not X509V3_EXT_REQ_add_nconf(
                     reqdata, ext_ctx, extn_section, req):

From f1ba856d62dcb859cbf33177738c7c2483eee65d Mon Sep 17 00:00:00 2001
From: Stanislav Laznicka <slazn...@redhat.com>
Date: Wed, 20 Sep 2017 11:50:26 +0200
Subject: [PATCH 3/7] csrgen: accept public key info as Bytes

cert_get_requestdata() method is meant for internal use only and
is never passed a file. Make its parameter public_key_info Bytes
to better represent what's actually being passed to it.

https://pagure.io/freeipa/issue/7131
---
 ipaclient/plugins/cert.py   | 2 +-
 ipaclient/plugins/csrgen.py | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/ipaclient/plugins/cert.py b/ipaclient/plugins/cert.py
index d5daaf3a15..d7011e67a4 100644
--- a/ipaclient/plugins/cert.py
+++ b/ipaclient/plugins/cert.py
@@ -132,7 +132,7 @@ def forward(self, csr=None, **options):
             response = self.api.Command.cert_get_requestdata(
                 profile_id=profile_id,
                 principal=options.get('principal'),
-                public_key_info=unicode(pubkey_info_b64))
+                public_key_info=pubkey_info_b64)
 
             req_info_b64 = response['result']['request_info']
             req_info = base64.b64decode(req_info_b64)
diff --git a/ipaclient/plugins/csrgen.py b/ipaclient/plugins/csrgen.py
index d18a90c211..01c75f4bcc 100644
--- a/ipaclient/plugins/csrgen.py
+++ b/ipaclient/plugins/csrgen.py
@@ -11,7 +11,7 @@
 from ipalib import output
 from ipalib import util
 from ipalib.frontend import Local, Str
-from ipalib.parameters import File, Principal
+from ipalib.parameters import Bytes, Principal
 from ipalib.plugable import Registry
 from ipalib.text import _
 from ipapython import dogtag
@@ -52,7 +52,7 @@ class cert_get_requestdata(Local):
             label=_('Profile ID'),
             doc=_('CSR Generation Profile to use'),
         ),
-        File(
+        Bytes(
             'public_key_info',
             label=_('Subject Public Key Info'),
             doc=_('DER-encoded SubjectPublicKeyInfo structure'),

From de2f11330fc162b50ddffaa7ba9010ca697f5dd0 Mon Sep 17 00:00:00 2001
From: Stanislav Laznicka <slazn...@redhat.com>
Date: Wed, 20 Sep 2017 12:29:08 +0200
Subject: [PATCH 4/7] csrgen: update docstring for py3

https://pagure.io/freeipa/issue/7131
---
 ipaclient/csrgen.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ipaclient/csrgen.py b/ipaclient/csrgen.py
index a22ccfb161..6fc3495e6b 100644
--- a/ipaclient/csrgen.py
+++ b/ipaclient/csrgen.py
@@ -396,7 +396,7 @@ def get_subject_public_key_info(self):
     def sign_csr(self, certification_request_info):
         """Sign a CertificationRequestInfo.
 
-        Returns: str, a DER-encoded signed CSR.
+        :returns: bytes, a DER-encoded signed CSR.
         """
         raise NotImplementedError('Use a subclass of CSRLibraryAdaptor')
 

From 974501197d8b7c4e29b315a68a4710fa15638aff Mon Sep 17 00:00:00 2001
From: Stanislav Laznicka <slazn...@redhat.com>
Date: Wed, 20 Sep 2017 12:32:16 +0200
Subject: [PATCH 5/7] parameters: relax type checks

The type checks in ipalib.parameters were too strict. An object
that inherits from a type should implement its public interface.
This should allow us checking for types of objects whose class
implementations are private to a module but they implement a certain
public interface (which is typical for e.g. python-cryptography).

https://pagure.io/freeipa/issue/7131
---
 ipalib/parameters.py | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/ipalib/parameters.py b/ipalib/parameters.py
index 81586e2c92..fa0c813a47 100644
--- a/ipalib/parameters.py
+++ b/ipalib/parameters.py
@@ -848,8 +848,10 @@ def _convert_scalar(self, value, index=None):
         """
         Convert a single scalar value.
         """
-        if type(value) in self.allowed_types:
-            return value
+        for t in self.allowed_types:
+            if isinstance(value, t):
+                return value
+
         raise ConversionError(name=self.name, error=ugettext(self.type_error))
 
     def validate(self, value, supplied=None):
@@ -879,7 +881,10 @@ def validate(self, value, supplied=None):
             self._validate_scalar(value)
 
     def _validate_scalar(self, value, index=None):
-        if type(value) not in self.allowed_types:
+        for t in self.allowed_types:
+            if isinstance(value, t):
+                break
+        else:
             raise TypeError(
                 TYPE_ERROR % (self.name, self.type, value, type(value))
             )

From 9d7280757e9db881d760b396ad7e06c358f23ba7 Mon Sep 17 00:00:00 2001
From: Stanislav Laznicka <slazn...@redhat.com>
Date: Fri, 22 Sep 2017 14:52:36 +0200
Subject: [PATCH 6/7] 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
---
 API.txt                                            |  2 +-
 ipaclient/plugins/cert.py                          |  3 --
 ipalib/parameters.py                               | 45 +++++++++++++++++++++-
 ipalib/rpc.py                                      |  5 +++
 ipaserver/plugins/cert.py                          | 38 ++++--------------
 .../test_xmlrpc/test_caacl_profile_enforcement.py  |  4 +-
 ipatests/test_xmlrpc/test_cert_plugin.py           | 10 ++---
 7 files changed, 64 insertions(+), 43 deletions(-)

diff --git a/API.txt b/API.txt
index 4b06a96923..0526d5a902 100644
--- a/API.txt
+++ b/API.txt
@@ -783,7 +783,7 @@ option: Str('version?')
 output: Output('result')
 command: cert_request/1
 args: 1,9,3
-arg: Str('csr', cli_name='csr_file')
+arg: CertificateSigningRequest('csr', cli_name='csr_file')
 option: Flag('add', autofill=True, default=False)
 option: Flag('all', autofill=True, cli_name='all', default=False)
 option: Str('cacn?', autofill=True, cli_name='ca', default=u'ipa')
diff --git a/ipaclient/plugins/cert.py b/ipaclient/plugins/cert.py
index d7011e67a4..0377c511c7 100644
--- a/ipaclient/plugins/cert.py
+++ b/ipaclient/plugins/cert.py
@@ -143,9 +143,6 @@ def forward(self, csr=None, **options):
                 raise errors.CertificateOperationError(
                     error=(_('Generated CSR was empty')))
 
-            # cert_request requires the CSR to be base64-encoded (but PEM
-            # header and footer are not required)
-            csr = unicode(base64.b64encode(csr))
         else:
             if database is not None or private_key is not None:
                 raise errors.MutuallyExclusiveError(reason=_(
diff --git a/ipalib/parameters.py b/ipalib/parameters.py
index fa0c813a47..5d3bfa9fcb 100644
--- a/ipalib/parameters.py
+++ b/ipalib/parameters.py
@@ -115,12 +115,14 @@
 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 ipapython import kerberos
 from ipapython.dn import DN
 from ipapython.dnsutil import DNSName
@@ -1452,6 +1454,45 @@ def _convert_scalar(self, value, index=None):
         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 _convert_scalar(self, value, index=None):
+        """
+        :param value: either DER csr or base64 encoded csr
+        :returns: bytes representing value converted to DER format
+        """
+        if isinstance(value, bytes):
+            try:
+                value = value.decode('ascii')
+            except UnicodeDecodeError:
+                # value is possibly a DER-encoded csr
+                pass
+
+        if isinstance(value, unicode):
+            # if we received unicodes right away or we got them after the
+            # decoding, we will now try to receive DER-csr
+            try:
+                value = base64.b64decode(value)
+            except (TypeError, ValueError) as e:
+                raise Base64DecodeError(reason=str(e))
+
+        if isinstance(value, bytes):
+            # we now only have either bytes or a CertificateSigningRequest
+            # object. If it's bytes, make it a CertificateSigningRequest object
+            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).
diff --git a/ipalib/rpc.py b/ipalib/rpc.py
index 4b81e89975..c9d47d95ff 100644
--- a/ipalib/rpc.py
+++ b/ipalib/rpc.py
@@ -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 @@ def __init__(self, version, _identity=_identity):
             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:
diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py
index 202d92dfd5..e465c3a838 100644
--- a/ipaserver/plugins/cert.py
+++ b/ipaserver/plugins/cert.py
@@ -40,7 +40,8 @@
 from ipalib.crud import Create, PKQuery, Retrieve, Search
 from ipalib.frontend import Method, Object
 from ipalib.parameters import (
-    Bytes, Certificate, DateTime, DNParam, DNSNameParam, Principal
+    Bytes, Certificate, CertificateSigningRequest, DateTime, DNParam,
+    DNSNameParam, Principal
 )
 from ipalib.plugable import Registry
 from .virtual import VirtualCommand
@@ -254,22 +255,6 @@ def convert_pkidatetime(value):
     return x509.format_datetime(value)
 
 
-def validate_csr(ugettext, csr):
-    """
-    Ensure the CSR is base64-encoded and can be decoded by our PKCS#10
-    parser.
-    """
-    if api.env.context == 'cli':
-        # If we are passed in a pointer to a valid file on the client side
-        # escape and let the load_files() handle things
-        if csr and os.path.exists(csr):
-            return
-    try:
-        pkcs10.load_certificate_request(csr)
-    except (TypeError, ValueError) as e:
-        raise errors.CertificateOperationError(error=_('Failure decoding Certificate Signing Request: %s') % e)
-
-
 def normalize_serial_number(num):
     """
     Convert a SN given in decimal or hexadecimal.
@@ -616,11 +601,10 @@ class cert_request(Create, BaseCertMethod, VirtualCommand):
     attr_name = 'request'
 
     takes_args = (
-        Str(
-            'csr', validate_csr,
+        CertificateSigningRequest(
+            'csr',
             label=_('CSR'),
             cli_name='csr_file',
-            noextrawhitespace=False,
         ),
     )
     operation="request certificate"
@@ -725,13 +709,7 @@ def execute(self, csr, all=False, raw=False, chain=False, **kw):
                 caacl_check(principal, ca, profile_id)
 
         try:
-            csr_obj = pkcs10.load_certificate_request(csr)
-        except ValueError as e:
-            raise errors.CertificateOperationError(
-                error=_("Failure decoding Certificate Signing Request: %s") % e)
-
-        try:
-            ext_san = csr_obj.extensions.get_extension_for_oid(
+            ext_san = csr.extensions.get_extension_for_oid(
                 cryptography.x509.oid.ExtensionOID.SUBJECT_ALTERNATIVE_NAME)
         except cryptography.x509.extensions.ExtensionNotFound:
             ext_san = None
@@ -739,7 +717,7 @@ def execute(self, csr, all=False, raw=False, chain=False, **kw):
         # Ensure that the DN in the CSR matches the principal
         #
         # We only look at the "most specific" CN value
-        cns = csr_obj.subject.get_attributes_for_oid(
+        cns = csr.subject.get_attributes_for_oid(
                 cryptography.x509.oid.NameOID.COMMON_NAME)
         if len(cns) == 0:
             raise errors.ValidationError(name='csr',
@@ -772,7 +750,7 @@ def execute(self, csr, all=False, raw=False, chain=False, **kw):
             # check email address
             #
             # fail if any email addr from DN does not appear in ldap entry
-            email_addrs = csr_obj.subject.get_attributes_for_oid(
+            email_addrs = csr.subject.get_attributes_for_oid(
                     cryptography.x509.oid.NameOID.EMAIL_ADDRESS)
             csr_emails = [attr.value for attr in email_addrs]
             if not _emails_are_valid(csr_emails,
@@ -888,7 +866,7 @@ def execute(self, csr, all=False, raw=False, chain=False, **kw):
             # re-serialise to PEM, in case the user-supplied data has
             # extraneous material that will cause Dogtag to freak out
             # keep it as string not bytes, it is required later
-            csr_pem = csr_obj.public_bytes(
+            csr_pem = csr.public_bytes(
                 serialization.Encoding.PEM).decode('utf-8')
             result = self.Backend.ra.request_certificate(
                 csr_pem, profile_id, ca_id, request_type=request_type)
diff --git a/ipatests/test_xmlrpc/test_caacl_profile_enforcement.py b/ipatests/test_xmlrpc/test_caacl_profile_enforcement.py
index fa474c64ae..2577b4de0b 100644
--- a/ipatests/test_xmlrpc/test_caacl_profile_enforcement.py
+++ b/ipatests/test_xmlrpc/test_caacl_profile_enforcement.py
@@ -53,8 +53,8 @@ def generate_user_csr(username, domain=None):
              '-config', prepare_config(
                  CERT_OPENSSL_CONFIG_TEMPLATE, csr_values)])
 
-        with open(csr_file.name, 'r') as f:
-            csr = unicode(f.read())
+        with open(csr_file.name, 'rb') as f:
+            csr = f.read()
 
     return csr
 
diff --git a/ipatests/test_xmlrpc/test_cert_plugin.py b/ipatests/test_xmlrpc/test_cert_plugin.py
index 0de5b75346..06a008a9ec 100644
--- a/ipatests/test_xmlrpc/test_cert_plugin.py
+++ b/ipatests/test_xmlrpc/test_cert_plugin.py
@@ -121,7 +121,7 @@ def generateCSR(self, subject):
                            "-f", self.pwname,
                            "-a",
                            ])
-        with open(self.reqfile, "r") as fp:
+        with open(self.reqfile, "rb") as fp:
             data = fp.read()
         return data
 
@@ -149,7 +149,7 @@ def test_0001_cert_add(self):
         # First create the host that will use this policy
         assert 'result' in api.Command['host_add'](self.host_fqdn, force=True)
 
-        csr = unicode(self.generateCSR(str(self.subject)))
+        csr = self.generateCSR(str(self.subject))
         with assert_raises(errors.NotFound):
             api.Command['cert_request'](csr, principal=self.service_princ)
 
@@ -160,7 +160,7 @@ def test_0002_cert_add(self):
         # Our host should exist from previous test
         global cert, sn
 
-        csr = unicode(self.generateCSR(str(self.subject)))
+        csr = self.generateCSR(str(self.subject))
         res = api.Command['cert_request'](csr, principal=self.service_princ, add=True)['result']
         assert DN(res['subject']) == self.subject
         assert 'cacn' in res
@@ -203,7 +203,7 @@ def test_0006_cert_renew(self):
         """
         global newcert
 
-        csr = unicode(self.generateCSR(str(self.subject)))
+        csr = self.generateCSR(str(self.subject))
         res = api.Command['cert_request'](csr, principal=self.service_princ)['result']
         assert DN(res['subject']) == self.subject
         # save the cert for the service_show/find tests
@@ -473,7 +473,7 @@ def revoke_cert(self, reason):
         assert 'result' in api.Command['host_add'](self.host_fqdn, force=True)
 
         # generate CSR, request certificate, obtain serial number
-        self.csr = unicode(self.generateCSR(str(self.subject)))
+        self.csr = self.generateCSR(str(self.subject))
         res = api.Command['cert_request'](self.csr,
                                           principal=self.service_princ,
                                           add=True, all=True)['result']

From 3719b53975379047b64fc4b06c7323eb01a543d5 Mon Sep 17 00:00:00 2001
From: Stanislav Laznicka <slazn...@redhat.com>
Date: Mon, 25 Sep 2017 09:18:41 +0200
Subject: [PATCH 7/7] Remove pkcs10 module contents

This removes pkcs10 module contents and adds a warning message
about its future removal.

https://pagure.io/freeipa/issue/7131
---
 ipalib/pkcs10.py                    |  60 ++-------------
 ipatests/test_pkcs10/__init__.py    |  22 ------
 ipatests/test_pkcs10/test0.csr      |  12 ---
 ipatests/test_pkcs10/test1.csr      |  13 ----
 ipatests/test_pkcs10/test2.csr      |  15 ----
 ipatests/test_pkcs10/test3.csr      |   3 -
 ipatests/test_pkcs10/test4.csr      |   4 -
 ipatests/test_pkcs10/test5.csr      |  20 -----
 ipatests/test_pkcs10/test_pkcs10.py | 141 ------------------------------------
 9 files changed, 6 insertions(+), 284 deletions(-)
 delete mode 100644 ipatests/test_pkcs10/__init__.py
 delete mode 100644 ipatests/test_pkcs10/test0.csr
 delete mode 100644 ipatests/test_pkcs10/test1.csr
 delete mode 100644 ipatests/test_pkcs10/test2.csr
 delete mode 100644 ipatests/test_pkcs10/test3.csr
 delete mode 100644 ipatests/test_pkcs10/test4.csr
 delete mode 100644 ipatests/test_pkcs10/test5.csr
 delete mode 100644 ipatests/test_pkcs10/test_pkcs10.py

diff --git a/ipalib/pkcs10.py b/ipalib/pkcs10.py
index 39ec95c68a..2756c85682 100644
--- a/ipalib/pkcs10.py
+++ b/ipalib/pkcs10.py
@@ -1,56 +1,8 @@
-# Authors:
-#   Rob Crittenden <rcrit...@redhat.com>
-#
-# Copyright (C) 2010  Red Hat
-# see file 'COPYING' for use and warranty information
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
 from __future__ import print_function
+import sys
 
-import binascii
-from cryptography.hazmat.backends import default_backend
-import cryptography.x509
-
-
-def strip_header(csr):
-    """
-    Remove the header and footer (and surrounding material) from a CSR.
-    """
-    headerlen = 40
-    s = csr.find("-----BEGIN NEW CERTIFICATE REQUEST-----")
-    if s == -1:
-        headerlen = 36
-        s = csr.find("-----BEGIN CERTIFICATE REQUEST-----")
-    if s >= 0:
-        e = csr.find("-----END")
-        csr = csr[s+headerlen:e]
-
-    return csr
-
-
-def load_certificate_request(data):
-    """
-    Load a PEM or base64-encoded PKCS #10 certificate request.
-
-    :return: a python-cryptography ``Certificate`` object.
-    :raises: ``ValueError`` if unable to load the request
-
-    """
-    data = strip_header(data)
-    try:
-        data = binascii.a2b_base64(data)
-    except binascii.Error as e:
-        raise ValueError(e)
-    return cryptography.x509.load_der_x509_csr(data, default_backend())
+print(
+    "ipalib.pkcs10 module is deprecated and will be removed in FreeIPA 4.6. "
+    "To load CSRs, please, use python-cryptography instead.",
+    file=sys.stderr
+)
diff --git a/ipatests/test_pkcs10/__init__.py b/ipatests/test_pkcs10/__init__.py
deleted file mode 100644
index cd03658cf9..0000000000
--- a/ipatests/test_pkcs10/__init__.py
+++ /dev/null
@@ -1,22 +0,0 @@
-# Authors:
-#   Rob Crittenden <rcrit...@redhat.com>
-#
-# Copyright (C) 2009  Red Hat
-# see file 'COPYING' for use and warranty information
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-"""
-Sub-package containing unit tests for `pkcs10` package.
-"""
diff --git a/ipatests/test_pkcs10/test0.csr b/ipatests/test_pkcs10/test0.csr
deleted file mode 100644
index eadfb70b4f..0000000000
--- a/ipatests/test_pkcs10/test0.csr
+++ /dev/null
@@ -1,12 +0,0 @@
------BEGIN NEW CERTIFICATE REQUEST-----
-MIIBjjCB+AIBADBPMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEQ
-MA4GA1UEChMHRXhhbXBsZTEZMBcGA1UEAxMQdGVzdC5leGFtcGxlLmNvbTCBnzAN
-BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAyxsN5dmvyKiw+5nyrcO3a61sivZRg+ja
-kyNIyUo+tIUiYwTdpPESAHTWRlk0XhydauAkWfOIN7pR3a5Z+kQw8W7F+DuZze2M
-6wRNmN+NTrTlqnKOiMHBXhIM0Qxrx68GDctYqtnKTVT94FvvLl9XYVdUEi2ePTc2
-Nyfr1z66+W0CAwEAAaAAMA0GCSqGSIb3DQEBBQUAA4GBAIf3r+Y6WHrFnttUqDow
-9/UCHtCeQlQoJqjjxi5wcjbkGwTgHbx/BPOd/8OVaHElboMXLGaZx+L/eFO6E9Yg
-mDOYv3OsibDFGaEhJrU8EnfuFZKnbrGeSC9Hkqrq+3OjqacaPla5N7MHKbfLY377
-ddbOHKzR0sURZ+ro4z3fATW2
------END NEW CERTIFICATE REQUEST-----
-
diff --git a/ipatests/test_pkcs10/test1.csr b/ipatests/test_pkcs10/test1.csr
deleted file mode 100644
index 0dad3ae1e2..0000000000
--- a/ipatests/test_pkcs10/test1.csr
+++ /dev/null
@@ -1,13 +0,0 @@
------BEGIN NEW CERTIFICATE REQUEST-----
-MIIBwDCCASkCAQAwTzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWEx
-EDAOBgNVBAoTB0V4YW1wbGUxGTAXBgNVBAMTEHRlc3QuZXhhbXBsZS5jb20wgZ8w
-DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMK+3uy1CGwek8jutw4UO62YTpkmStlw
-cKPEjTER7Ra1a1wyWJTo1mMnPhVia0GODeq8ERPgcIckCVogBu8+gL6g8NevaBNv
-ij1XWU08BEQqmoqAkrFiI8EdDckKYrSoXo2cg1fiTGzlG8AWtr5eT0op5jBBo0J6
-qXX5Sf6e+n+nAgMBAAGgMTAvBgkqhkiG9w0BCQ4xIjAgMB4GA1UdEQQXMBWCE3Rl
-c3Rsb3cuZXhhbXBsZS5jb20wDQYJKoZIhvcNAQEFBQADgYEAwRDa7ZOaym9mAUH7
-hudbvsRkqXHehgf51uMUq0OC9hQ6vPLWqUMAod05lxn3Tnvq6a/fVK0ybgCH5Ld7
-qpAcUruYdj7YxkFfuBc1dpAK6h94rVsJXFCWIMEZm9Fe7n5RERjhO6h2IRSXBHFz
-QIszvqBamm/W1ONKdQSM2g+M4BQ=
------END NEW CERTIFICATE REQUEST-----
-
diff --git a/ipatests/test_pkcs10/test2.csr b/ipatests/test_pkcs10/test2.csr
deleted file mode 100644
index ccc47f8909..0000000000
--- a/ipatests/test_pkcs10/test2.csr
+++ /dev/null
@@ -1,15 +0,0 @@
------BEGIN NEW CERTIFICATE REQUEST-----
-MIICETCCAXoCAQAwTzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWEx
-EDAOBgNVBAoTB0V4YW1wbGUxGTAXBgNVBAMTEHRlc3QuZXhhbXBsZS5jb20wgZ8w
-DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOXfP8LeiU7g6wLCclgkT1lVskK+Lxm1
-6ijE4LmEQBk5nn2P46im+E/UOgTddbDo5cdJlkoCnqXkO4RkqJckXYDxfI34KL3C
-CRFPvOa5Sg02m1x5Rg3boZfS6NciP62lRp0SI+0TCt3F16wYZxMahVIOXjbJ6Lu5
-mGjNn7XaWJhFAgMBAAGggYEwfwYJKoZIhvcNAQkOMXIwcDAeBgNVHREEFzAVghN0
-ZXN0bG93LmV4YW1wbGUuY29tME4GA1UdHwRHMEUwQ6BBoD+GHGh0dHA6Ly9jYS5l
-eGFtcGxlLmNvbS9teS5jcmyGH2h0dHA6Ly9vdGhlci5leGFtcGxlLmNvbS9teS5j
-cmwwDQYJKoZIhvcNAQEFBQADgYEAkv8pppcgGhX7erJmvg9r2UHrRriuKaOYgKZQ
-lf/eBt2N0L2mV4QvCY82H7HWuE+7T3mra9ikfvz0nYkPJQe2gntjZzECE0Jt5LWR
-UZOFwX8N6wrX11U2xu0NlvsbjU6siWd6OZjZ1p5/V330lzut/q3CNzaAcW1Fx3wL
-sV5SXSw=
------END NEW CERTIFICATE REQUEST-----
-
diff --git a/ipatests/test_pkcs10/test3.csr b/ipatests/test_pkcs10/test3.csr
deleted file mode 100644
index 82c84d1543..0000000000
--- a/ipatests/test_pkcs10/test3.csr
+++ /dev/null
@@ -1,3 +0,0 @@
------BEGIN NEW CERTIFICATE REQUEST-----
-VGhpcyBpcyBhbiBpbnZhbGlkIENTUg==
------END NEW CERTIFICATE REQUEST-----
diff --git a/ipatests/test_pkcs10/test4.csr b/ipatests/test_pkcs10/test4.csr
deleted file mode 100644
index 9f08b802b6..0000000000
--- a/ipatests/test_pkcs10/test4.csr
+++ /dev/null
@@ -1,4 +0,0 @@
------BEGIN NEW CERTIFICATE REQUEST-----
-Invalidate data
------END NEW CERTIFICATE REQUEST-----
-
diff --git a/ipatests/test_pkcs10/test5.csr b/ipatests/test_pkcs10/test5.csr
deleted file mode 100644
index 41c3c1f3d6..0000000000
--- a/ipatests/test_pkcs10/test5.csr
+++ /dev/null
@@ -1,20 +0,0 @@
-
-Certificate request generated by Netscape certutil
-Phone: (not specified)
-
-Common Name: test.example.com
-Email: (not specified)
-Organization: IPA
-State: (not specified)
-Country: (not specified)
-
------BEGIN NEW CERTIFICATE REQUEST-----
-MIIBaDCB0gIBADApMQwwCgYDVQQKEwNJUEExGTAXBgNVBAMTEHRlc3QuZXhhbXBs
-ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPnSCLwl7IytP2HC7+zv
-nI2fe6oRCE/J8K1jIoiqS9engx3Yfe4kaXWWzcwmuUV57VhUmWDEQIbSREPdrVSi
-tWC55ilGmPOAEw+mP4qg6Ctb+d8Egmy1JVrpIYCLNXvEd3dAaimB0J+K3hKFRyHI
-2MzrIuFqqohRijkDLwB8oVVdAgMBAAGgADANBgkqhkiG9w0BAQUFAAOBgQACt37K
-j+RMEbqG8s0Uxs3FhcfiAx8Do99CDizY/b7hZEgMyG4dLmm+vSCBbxBrG5oMlxJD
-dxnpk0PQSknNkJVrCS/J1OTpOPRTi4VKATT3tHJAfDbWZTwcSelUCLQ4lREiuT3D
-WP4vKrLIxDJDb+/mwuV7WWo34E6MD9iTB1xINg==
------END NEW CERTIFICATE REQUEST-----
diff --git a/ipatests/test_pkcs10/test_pkcs10.py b/ipatests/test_pkcs10/test_pkcs10.py
deleted file mode 100644
index df50df0987..0000000000
--- a/ipatests/test_pkcs10/test_pkcs10.py
+++ /dev/null
@@ -1,141 +0,0 @@
-# Authors:
-#   Rob Crittenden <rcrit...@redhat.com>
-#
-# Copyright (C) 2009  Red Hat
-# see file 'COPYING' for use and warranty information
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-"""
-Test the `pkcs10.py` module.
-"""
-
-import nose
-from ipalib import pkcs10
-from ipapython import ipautil
-import pytest
-import os
-import cryptography.x509
-
-
-@pytest.mark.tier0
-class test_update(object):
-    """
-    Test the PKCS#10 Parser.
-    """
-
-    def setup(self):
-        self.testdir = os.path.abspath(os.path.dirname(__file__))
-        if not ipautil.file_exists(os.path.join(self.testdir,
-                                                "test0.csr")):
-            raise nose.SkipTest("Unable to find test update files")
-
-    def read_file(self, filename):
-        with open(os.path.join(self.testdir, filename), "r") as fp:
-            data = fp.read()
-        return data
-
-    def test_0(self):
-        """
-        Test simple CSR with no attributes
-        """
-        csr = pkcs10.load_certificate_request(self.read_file("test0.csr"))
-
-        subject = csr.subject
-
-        cn = subject.get_attributes_for_oid(
-                cryptography.x509.NameOID.COMMON_NAME)[-1].value
-        assert(cn == 'test.example.com')
-        st = subject.get_attributes_for_oid(
-                cryptography.x509.NameOID.STATE_OR_PROVINCE_NAME)[-1].value
-        assert(st == 'California')
-        c = subject.get_attributes_for_oid(
-                cryptography.x509.NameOID.COUNTRY_NAME)[-1].value
-        assert(c == 'US')
-
-    def test_1(self):
-        """
-        Test CSR with subject alt name
-        """
-        csr = self.read_file("test1.csr")
-        request = pkcs10.load_certificate_request(csr)
-
-        subject = request.subject
-
-        cn = subject.get_attributes_for_oid(
-                cryptography.x509.NameOID.COMMON_NAME)[-1].value
-        assert(cn == 'test.example.com')
-        st = subject.get_attributes_for_oid(
-                cryptography.x509.NameOID.STATE_OR_PROVINCE_NAME)[-1].value
-        assert(st == 'California')
-        c = subject.get_attributes_for_oid(
-                cryptography.x509.NameOID.COUNTRY_NAME)[-1].value
-        assert(c == 'US')
-
-        san = request.extensions.get_extension_for_oid(
-                cryptography.x509.ExtensionOID.SUBJECT_ALTERNATIVE_NAME).value
-        dns = san.get_values_for_type(cryptography.x509.DNSName)
-        assert dns[0] == 'testlow.example.com'
-
-    def test_2(self):
-        """
-        Test CSR with subject alt name and a list of CRL distribution points
-        """
-        csr = self.read_file("test2.csr")
-        request = pkcs10.load_certificate_request(csr)
-
-        subject = request.subject
-
-        cn = subject.get_attributes_for_oid(
-                cryptography.x509.NameOID.COMMON_NAME)[-1].value
-        assert(cn == 'test.example.com')
-        st = subject.get_attributes_for_oid(
-                cryptography.x509.NameOID.STATE_OR_PROVINCE_NAME)[-1].value
-        assert(st == 'California')
-        c = subject.get_attributes_for_oid(
-                cryptography.x509.NameOID.COUNTRY_NAME)[-1].value
-        assert(c == 'US')
-
-        san = request.extensions.get_extension_for_oid(
-                cryptography.x509.ExtensionOID.SUBJECT_ALTERNATIVE_NAME).value
-        dns = san.get_values_for_type(cryptography.x509.DNSName)
-        assert dns[0] == 'testlow.example.com'
-
-        crldps = request.extensions.get_extension_for_oid(
-                cryptography.x509.ExtensionOID.CRL_DISTRIBUTION_POINTS).value
-        gns = []
-        for crldp in crldps:
-            gns.extend(crldp.full_name)
-        uris = [
-            u'http://ca.example.com/my.crl',
-            u'http://other.example.com/my.crl',
-        ]
-        for uri in uris:
-            assert cryptography.x509.UniformResourceIdentifier(uri) in gns
-
-    def test_3(self):
-        """
-        Test CSR with base64-encoded bogus data
-        """
-        csr = self.read_file("test3.csr")
-
-        with pytest.raises(ValueError):
-            pkcs10.load_certificate_request(csr)
-
-    def test_4(self):
-        """
-        Test CSR with badly formatted base64-encoded data
-        """
-        csr = self.read_file("test4.csr")
-        with pytest.raises(ValueError):
-            pkcs10.load_certificate_request(csr)
_______________________________________________
FreeIPA-devel mailing list -- freeipa-devel@lists.fedorahosted.org
To unsubscribe send an email to freeipa-devel-le...@lists.fedorahosted.org

Reply via email to