e8574e
Addtional patches that need to be partly reverted that are touching csrgen
e8574e
related files:
e8574e
e8574e
7b8a2af2197381058ca532d1ae206defb16fac88
e8574e
ac6568dcf58ec8d06df5493d14a28aa41845d4ef
e8574e
9c86d35a3f0af4a793fada7dfe726e9cc66782ea
e8574e
9836511a2b6d7cf48b1a54cb3158e5eac674081a
e8574e
b431e9b684df11c811892bd9d2a5711355f0076e
e8574e
e8574e
This is a collection of an existing patch to remove csrgen for 4.7.1 and
e8574e
additional patches that have been added for 4.7.90 pre1.
e8574e
e8574e
Additional reverted csrgen patches:
e8574e
e8574e
852618fd6529fbdd7b03077fae37c6fbbe45b51b
e8574e
0ac1d3ea62efd9751fcc59cea46bcdafe1f11c37
e8574e
7633d62d858c14523a99143aa0ff36f76bb4ff68
e8574e
53f87ee5cd9d19f6fb91a9a1eafc8ea798095954
e8574e
395a68d20887d0ac010e480e68b225d6dfeff726
e8574e
03786ad9f3bd5edc351040847b8a49c9cd9288b2
e8574e
c9d710a446d10aad72795e15bf041b87102628c1
e8574e
2b90c8a20e45ade9bfd27731cccc94a34cf3f61e
e8574e
61dde27f70b9f8dd1b57ad1fbc3744f3c380613a
e8574e
806784dbd9e69a89c7a705c89bf42ba1fd4265c9
e8574e
79378c90512a1cdd5f3d5ec6482e434caea06e01
e8574e
bd5a5012d24820b54cdca2955f5405b84de1178c
e8574e
26ab51ddf47f421f3404709052db89f08c05adaa
e8574e
a53e17830c3d4fd59a62248d4447491675c6a80e
e8574e
e7588ab2dc73e7f66ebc6cdcfb99470540e37731
e8574e
136c6c3e2a4f77a27f435efd4a1cd95c9e089314
e8574e
5420e9cfbe7803808b6e26d2dae64f2a6a50149a
e8574e
e8574e
Original patch from 4.7.1:
e8574e
b01884
From 468bcf90cb985e2b1eb394bd752dc39aa4b75582 Mon Sep 17 00:00:00 2001
b01884
From: Rob Crittenden <rcritten@redhat.com>
b01884
Date: Thu, 19 Jul 2018 18:37:18 -0400
b01884
Subject: [PATCH] Remove csrgen
b01884
b01884
This reverts commits:
b01884
* 72de679eb445c975ec70cd265d37d4927823ce5b
b01884
* 177f07e163d6d591a1e609d35e0a6f6f5347551e
b01884
* 80be18162921268be9c8981495c9e8a4de0c85cd
b01884
* 83e2c2b65eeb5a3aa4a59c0535e9177aac5e4637
b01884
* ada91c20588046bb147fc701718d3da4d2c080ca
b01884
* 4350dcdea22fd2284836315d0ae7d38733a7620e
b01884
* 39a5d9c5aae77687f67d9be02457733bdfb99ead
b01884
* a26cf0d7910dd4c0a4da08682b4be8d3d94ba520
b01884
* afd7c05d11432304bfdf183832a21d419f363689
b01884
* f1a1c6eca1b294f24174d7b0e1f78de46d9d5b05
b01884
* fc58eff6a3d7fe805e612b8b002304d8b9cd4ba9
b01884
* 10ef5947860f5098182b1f95c08c1158e2da15f9
b01884
b01884
https://bugzilla.redhat.com/show_bug.cgi?id=1432630
b01884
---
b01884
 freeipa.spec.in                                    |  14 -
b01884
 ipaclient/csrgen.py                                | 488 ---------------------
b01884
 ipaclient/csrgen/profiles/caIPAserviceCert.json    |  15 -
b01884
 ipaclient/csrgen/profiles/userCert.json            |  15 -
b01884
 ipaclient/csrgen/rules/dataDNS.json                |   8 -
b01884
 ipaclient/csrgen/rules/dataEmail.json              |   8 -
b01884
 ipaclient/csrgen/rules/dataHostCN.json             |   8 -
b01884
 ipaclient/csrgen/rules/dataSubjectBase.json        |   8 -
b01884
 ipaclient/csrgen/rules/dataUsernameCN.json         |   8 -
b01884
 ipaclient/csrgen/rules/syntaxSAN.json              |   8 -
b01884
 ipaclient/csrgen/rules/syntaxSubject.json          |   9 -
b01884
 ipaclient/csrgen/templates/openssl_base.tmpl       |  17 -
b01884
 ipaclient/csrgen/templates/openssl_macros.tmpl     |  29 --
b01884
 ipaclient/csrgen_ffi.py                            | 331 --------------
b01884
 ipaclient/plugins/cert.py                          |  80 ----
b01884
 ipaclient/plugins/csrgen.py                        | 128 ------
b01884
 ipaclient/setup.py                                 |   8 -
b01884
 .../data/test_csrgen/configs/caIPAserviceCert.conf |  16 -
b01884
 .../data/test_csrgen/configs/userCert.conf         |  16 -
b01884
 .../data/test_csrgen/profiles/profile.json         |   8 -
b01884
 .../data/test_csrgen/rules/basic.json              |   5 -
b01884
 .../data/test_csrgen/rules/options.json            |   8 -
b01884
 .../data/test_csrgen/templates/identity_base.tmpl  |   1 -
b01884
 ipatests/test_ipaclient/test_csrgen.py             | 304 -------------
b01884
 24 files changed, 1540 deletions(-)
b01884
 delete mode 100644 ipaclient/csrgen.py
b01884
 delete mode 100644 ipaclient/csrgen/profiles/caIPAserviceCert.json
b01884
 delete mode 100644 ipaclient/csrgen/profiles/userCert.json
b01884
 delete mode 100644 ipaclient/csrgen/rules/dataDNS.json
b01884
 delete mode 100644 ipaclient/csrgen/rules/dataEmail.json
b01884
 delete mode 100644 ipaclient/csrgen/rules/dataHostCN.json
b01884
 delete mode 100644 ipaclient/csrgen/rules/dataSubjectBase.json
b01884
 delete mode 100644 ipaclient/csrgen/rules/dataUsernameCN.json
b01884
 delete mode 100644 ipaclient/csrgen/rules/syntaxSAN.json
b01884
 delete mode 100644 ipaclient/csrgen/rules/syntaxSubject.json
b01884
 delete mode 100644 ipaclient/csrgen/templates/openssl_base.tmpl
b01884
 delete mode 100644 ipaclient/csrgen/templates/openssl_macros.tmpl
b01884
 delete mode 100644 ipaclient/csrgen_ffi.py
b01884
 delete mode 100644 ipaclient/plugins/csrgen.py
b01884
 delete mode 100644 ipatests/test_ipaclient/data/test_csrgen/configs/caIPAserviceCert.conf
b01884
 delete mode 100644 ipatests/test_ipaclient/data/test_csrgen/configs/userCert.conf
b01884
 delete mode 100644 ipatests/test_ipaclient/data/test_csrgen/profiles/profile.json
b01884
 delete mode 100644 ipatests/test_ipaclient/data/test_csrgen/rules/basic.json
b01884
 delete mode 100644 ipatests/test_ipaclient/data/test_csrgen/rules/options.json
b01884
 delete mode 100644 ipatests/test_ipaclient/data/test_csrgen/templates/identity_base.tmpl
b01884
 delete mode 100644 ipatests/test_ipaclient/test_csrgen.py
b01884
e8574e
diff -urN freeipa-4.8.0/freeipa.spec.in freeipa-4.8.0.removed_csrgen/freeipa.spec.in
e8574e
--- freeipa-4.8.0/freeipa.spec.in	2019-06-29 10:01:30.458735813 +0200
e8574e
+++ freeipa-4.8.0.removed_csrgen/freeipa.spec.in	2019-07-03 13:24:38.471222723 +0200
e8574e
@@ -1247,13 +1247,6 @@
b01884
 %dir %{python3_sitelib}/ipaclient/remote_plugins/2_*
b01884
 %{python3_sitelib}/ipaclient/remote_plugins/2_*/*.py
b01884
 %{python3_sitelib}/ipaclient/remote_plugins/2_*/__pycache__/*.py*
b01884
-%dir %{python3_sitelib}/ipaclient/csrgen
b01884
-%dir %{python3_sitelib}/ipaclient/csrgen/profiles
b01884
-%{python3_sitelib}/ipaclient/csrgen/profiles/*.json
b01884
-%dir %{python3_sitelib}/ipaclient/csrgen/rules
b01884
-%{python3_sitelib}/ipaclient/csrgen/rules/*.json
b01884
-%dir %{python3_sitelib}/ipaclient/csrgen/templates
b01884
-%{python3_sitelib}/ipaclient/csrgen/templates/*.tmpl
b01884
 %{python3_sitelib}/ipaclient-*.egg-info
b01884
 
b01884
 
e8574e
diff -urN freeipa-4.8.0/ipaclient/csrgen/profiles/caIPAserviceCert.json freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/profiles/caIPAserviceCert.json
e8574e
--- freeipa-4.8.0/ipaclient/csrgen/profiles/caIPAserviceCert.json	2019-07-03 08:42:41.844539797 +0200
e8574e
+++ freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/profiles/caIPAserviceCert.json	1970-01-01 01:00:00.000000000 +0100
e8574e
@@ -1,15 +0,0 @@
e8574e
-[
e8574e
-    {
e8574e
-        "syntax": "syntaxSubject",
e8574e
-        "data": [
e8574e
-            "dataHostCN",
e8574e
-            "dataSubjectBase"
e8574e
-        ]
e8574e
-    },
e8574e
-    {
e8574e
-        "syntax": "syntaxSAN",
e8574e
-        "data": [
e8574e
-            "dataDNS"
e8574e
-        ]
e8574e
-    }
e8574e
-]
e8574e
diff -urN freeipa-4.8.0/ipaclient/csrgen/profiles/userCert.json freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/profiles/userCert.json
e8574e
--- freeipa-4.8.0/ipaclient/csrgen/profiles/userCert.json	2019-07-03 08:42:41.848539737 +0200
e8574e
+++ freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/profiles/userCert.json	1970-01-01 01:00:00.000000000 +0100
e8574e
@@ -1,15 +0,0 @@
e8574e
-[
e8574e
-    {
e8574e
-        "syntax": "syntaxSubject",
e8574e
-        "data": [
e8574e
-            "dataUsernameCN",
e8574e
-            "dataSubjectBase"
e8574e
-        ]
e8574e
-    },
e8574e
-    {
e8574e
-        "syntax": "syntaxSAN",
e8574e
-        "data": [
e8574e
-            "dataEmail"
e8574e
-        ]
e8574e
-    }
e8574e
-]
e8574e
diff -urN freeipa-4.8.0/ipaclient/csrgen/rules/dataDNS.json freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/rules/dataDNS.json
e8574e
--- freeipa-4.8.0/ipaclient/csrgen/rules/dataDNS.json	2019-07-03 08:42:41.853539663 +0200
e8574e
+++ freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/rules/dataDNS.json	1970-01-01 01:00:00.000000000 +0100
e8574e
@@ -1,8 +0,0 @@
e8574e
-{
e8574e
-  "rule": {
e8574e
-    "template": "DNS = {{subject.krbprincipalname.0.partition('/')[2].partition('@')[0]}}"
e8574e
-  },
e8574e
-  "options": {
e8574e
-    "data_source": "subject.krbprincipalname.0.partition('/')[2].partition('@')[0]"
e8574e
-  }
e8574e
-}
e8574e
diff -urN freeipa-4.8.0/ipaclient/csrgen/rules/dataEmail.json freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/rules/dataEmail.json
e8574e
--- freeipa-4.8.0/ipaclient/csrgen/rules/dataEmail.json	2019-07-03 08:42:41.857539603 +0200
e8574e
+++ freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/rules/dataEmail.json	1970-01-01 01:00:00.000000000 +0100
e8574e
@@ -1,8 +0,0 @@
e8574e
-{
e8574e
-  "rule": {
e8574e
-    "template": "email = {{subject.mail.0}}"
e8574e
-  },
e8574e
-  "options": {
e8574e
-    "data_source": "subject.mail.0"
e8574e
-  }
e8574e
-}
e8574e
diff -urN freeipa-4.8.0/ipaclient/csrgen/rules/dataHostCN.json freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/rules/dataHostCN.json
e8574e
--- freeipa-4.8.0/ipaclient/csrgen/rules/dataHostCN.json	2019-07-03 08:42:41.861539544 +0200
e8574e
+++ freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/rules/dataHostCN.json	1970-01-01 01:00:00.000000000 +0100
e8574e
@@ -1,8 +0,0 @@
e8574e
-{
e8574e
-  "rule": {
e8574e
-    "template": "CN={{subject.krbprincipalname.0.partition('/')[2].partition('@')[0]}}"
e8574e
-  },
e8574e
-  "options": {
e8574e
-    "data_source": "subject.krbprincipalname.0.partition('/')[2].partition('@')[0]"
e8574e
-  }
e8574e
-}
e8574e
diff -urN freeipa-4.8.0/ipaclient/csrgen/rules/dataSubjectBase.json freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/rules/dataSubjectBase.json
e8574e
--- freeipa-4.8.0/ipaclient/csrgen/rules/dataSubjectBase.json	2019-07-03 08:42:41.865539484 +0200
e8574e
+++ freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/rules/dataSubjectBase.json	1970-01-01 01:00:00.000000000 +0100
e8574e
@@ -1,8 +0,0 @@
e8574e
-{
e8574e
-  "rule": {
e8574e
-    "template": "{{config.ipacertificatesubjectbase.0}}"
e8574e
-  },
e8574e
-  "options": {
e8574e
-    "data_source": "config.ipacertificatesubjectbase.0"
e8574e
-  }
e8574e
-}
e8574e
diff -urN freeipa-4.8.0/ipaclient/csrgen/rules/dataUsernameCN.json freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/rules/dataUsernameCN.json
e8574e
--- freeipa-4.8.0/ipaclient/csrgen/rules/dataUsernameCN.json	2019-07-03 08:42:41.869539424 +0200
e8574e
+++ freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/rules/dataUsernameCN.json	1970-01-01 01:00:00.000000000 +0100
e8574e
@@ -1,8 +0,0 @@
e8574e
-{
e8574e
-  "rule": {
e8574e
-    "template": "CN={{subject.uid.0}}"
e8574e
-  },
e8574e
-  "options": {
e8574e
-    "data_source": "subject.uid.0"
e8574e
-  }
e8574e
-}
e8574e
diff -urN freeipa-4.8.0/ipaclient/csrgen/rules/syntaxSAN.json freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/rules/syntaxSAN.json
e8574e
--- freeipa-4.8.0/ipaclient/csrgen/rules/syntaxSAN.json	2019-07-03 08:42:41.874539350 +0200
e8574e
+++ freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/rules/syntaxSAN.json	1970-01-01 01:00:00.000000000 +0100
e8574e
@@ -1,8 +0,0 @@
e8574e
-{
e8574e
-  "rule": {
e8574e
-    "template": "subjectAltName = @{% call openssl.section() %}{{ datarules|join('\n') }}{% endcall %}"
e8574e
-  },
e8574e
-  "options": {
e8574e
-    "extension": true
e8574e
-  }
e8574e
-}
e8574e
diff -urN freeipa-4.8.0/ipaclient/csrgen/rules/syntaxSubject.json freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/rules/syntaxSubject.json
e8574e
--- freeipa-4.8.0/ipaclient/csrgen/rules/syntaxSubject.json	2019-07-03 08:42:41.878539290 +0200
e8574e
+++ freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/rules/syntaxSubject.json	1970-01-01 01:00:00.000000000 +0100
e8574e
@@ -1,9 +0,0 @@
e8574e
-{
e8574e
-  "rule": {
e8574e
-    "template": "distinguished_name = {% call openssl.section() %}{{ datarules|reverse|join('\n') }}{% endcall %}"
e8574e
-  },
e8574e
-  "options": {
e8574e
-    "required": true,
e8574e
-    "data_source_combinator": "and"
e8574e
-  }
e8574e
-}
e8574e
diff -urN freeipa-4.8.0/ipaclient/csrgen/templates/openssl_base.tmpl freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/templates/openssl_base.tmpl
e8574e
--- freeipa-4.8.0/ipaclient/csrgen/templates/openssl_base.tmpl	2019-07-03 08:42:41.882539231 +0200
e8574e
+++ freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/templates/openssl_base.tmpl	1970-01-01 01:00:00.000000000 +0100
e8574e
@@ -1,17 +0,0 @@
e8574e
-{% raw -%}
e8574e
-{% import "openssl_macros.tmpl" as openssl -%}
e8574e
-{% endraw -%}
e8574e
-[ req ]
e8574e
-prompt = no
e8574e
-encrypt_key = no
b01884
-
e8574e
-{{ parameters|join('\n') }}
e8574e
-{% raw %}{% set rendered_extensions -%}{% endraw %}
e8574e
-{{ extensions|join('\n') }}
e8574e
-{% raw -%}
e8574e
-{%- endset -%}
e8574e
-{% if rendered_extensions -%}
e8574e
-req_extensions = {% call openssl.section() %}{{ rendered_extensions }}{% endcall %}
e8574e
-{% endif %}
e8574e
-{{ openssl.openssl_sections|join('\n\n') }}
e8574e
-{%- endraw %}
e8574e
diff -urN freeipa-4.8.0/ipaclient/csrgen/templates/openssl_macros.tmpl freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/templates/openssl_macros.tmpl
e8574e
--- freeipa-4.8.0/ipaclient/csrgen/templates/openssl_macros.tmpl	2019-07-03 08:42:41.886539171 +0200
e8574e
+++ freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/templates/openssl_macros.tmpl	1970-01-01 01:00:00.000000000 +0100
e8574e
@@ -1,29 +0,0 @@
e8574e
-{# List containing rendered sections to be included at end #}
e8574e
-{% set openssl_sections = [] %}
b01884
-
e8574e
-{#
e8574e
-List containing one entry for each section name allocated. Because of
e8574e
-scoping rules, we need to use a list so that it can be a "per-render global"
e8574e
-that gets updated in place. Real globals are shared by all templates with the
e8574e
-same environment, and variables defined in the macro don't persist after the
e8574e
-macro invocation ends.
e8574e
-#}
e8574e
-{% set openssl_section_num = [] %}
b01884
-
e8574e
-{% macro section() -%}
e8574e
-{% set name -%}
e8574e
-sec{{ openssl_section_num|length -}}
e8574e
-{% endset -%}
e8574e
-{% do openssl_section_num.append('') -%}
e8574e
-{% set contents %}{{ caller() }}{% endset -%}
e8574e
-{% if contents -%}
e8574e
-{% set sectiondata = formatsection(name, contents) -%}
e8574e
-{% do openssl_sections.append(sectiondata) -%}
e8574e
-{% endif -%}
e8574e
-{{ name -}}
e8574e
-{% endmacro %}
e8574e
-
e8574e
-{% macro formatsection(name, contents) -%}
e8574e
-[ {{ name }} ]
e8574e
-{{ contents -}}
e8574e
-{% endmacro %}
e8574e
diff -urN freeipa-4.8.0/ipaclient/csrgen_ffi.py freeipa-4.8.0.removed_csrgen/ipaclient/csrgen_ffi.py
e8574e
--- freeipa-4.8.0/ipaclient/csrgen_ffi.py	2019-07-03 08:42:41.816540214 +0200
e8574e
+++ freeipa-4.8.0.removed_csrgen/ipaclient/csrgen_ffi.py	1970-01-01 01:00:00.000000000 +0100
e8574e
@@ -1,387 +0,0 @@
e8574e
-from cffi import FFI
e8574e
-import ctypes.util
b01884
-
b01884
-from ipalib import errors
b01884
-
e8574e
-_ffi = FFI()
b01884
-
e8574e
-_ffi.cdef('''
e8574e
-/* libcrypto/crypto.h */
e8574e
-unsigned long OpenSSL_version_num(void);
e8574e
-unsigned long SSLeay(void);
e8574e
-const char * OpenSSL_version(int t);
e8574e
-const char * SSLeay_version(int t);
b01884
-
e8574e
-#define OPENSSL_VERSION 0
e8574e
-''')
b01884
-
e8574e
-_libcrypto = _ffi.dlopen(ctypes.util.find_library('crypto'))
b01884
-
e8574e
-# SSLeay_version has been renamed with OpenSSL_version in OpenSSL 1.1.0
e8574e
-# LibreSSL has OpenSSL_version since 2.7.0
e8574e
-try:
e8574e
-    OpenSSL_version = _libcrypto.OpenSSL_version
e8574e
-except AttributeError:
e8574e
-    OpenSSL_version = _libcrypto.SSLeay_version
b01884
-
e8574e
-_version = OpenSSL_version(_libcrypto.OPENSSL_VERSION)
e8574e
-_version = _ffi.string(_version).decode('utf-8')
e8574e
-LIBRESSL = _version.startswith('LibreSSL')
e8574e
-if not _version.startswith("OpenSSL") and not LIBRESSL:
e8574e
-    raise ImportError("Only LibreSSL and OpenSSL are supported")
b01884
-
e8574e
-# SSLeay has been renamed with OpenSSL_version_num in OpenSSL 1.1.0
e8574e
-# LibreSSL has OpenSSL_version_num since 2.7.0
e8574e
-try:
e8574e
-    OpenSSL_version_num = _libcrypto.OpenSSL_version_num
e8574e
-except AttributeError:
e8574e
-    OpenSSL_version_num = _libcrypto.SSLeay
b01884
-
e8574e
-# OpenSSL_version_num()/SSLeay() returns the value of OPENSSL_VERSION_NUMBER
e8574e
-#
e8574e
-# OPENSSL_VERSION_NUMBER is a numeric release version identifier:
e8574e
-# MNNFFPPS: major minor fix patch status
e8574e
-# For example,
e8574e
-# 0x000906000 == 0.9.6 dev
e8574e
-# 0x000906023 == 0.9.6b beta 3
e8574e
-# 0x00090605f == 0.9.6e release
e8574e
-_openssl_version = OpenSSL_version_num()
b01884
-
e8574e
-_ffi.cdef('''
e8574e
-typedef ... CONF;
e8574e
-typedef ... CONF_METHOD;
e8574e
-typedef ... BIO;
e8574e
-typedef ... ipa_STACK_OF_CONF_VALUE;
b01884
-
e8574e
-/* openssl/conf.h */
e8574e
-typedef struct {
e8574e
-    char *section;
e8574e
-    char *name;
e8574e
-    char *value;
e8574e
-} CONF_VALUE;
b01884
-
e8574e
-CONF *NCONF_new(CONF_METHOD *meth);
e8574e
-void NCONF_free(CONF *conf);
e8574e
-int NCONF_load_bio(CONF *conf, BIO *bp, long *eline);
e8574e
-ipa_STACK_OF_CONF_VALUE *NCONF_get_section(const CONF *conf,
e8574e
-                                        const char *section);
e8574e
-char *NCONF_get_string(const CONF *conf, const char *group, const char *name);
b01884
-
e8574e
-/* openssl/safestack.h */
e8574e
-// int sk_CONF_VALUE_num(ipa_STACK_OF_CONF_VALUE *);
e8574e
-// CONF_VALUE *sk_CONF_VALUE_value(ipa_STACK_OF_CONF_VALUE *, int);
b01884
-
e8574e
-/* openssl/stack.h */
e8574e
-typedef ... _STACK;
b01884
-
e8574e
-int OPENSSL_sk_num(const _STACK *);
e8574e
-void *OPENSSL_sk_value(const _STACK *, int);
b01884
-
e8574e
-int sk_num(const _STACK *);
e8574e
-void *sk_value(const _STACK *, int);
b01884
-
e8574e
-/* openssl/bio.h */
e8574e
-BIO *BIO_new_mem_buf(const void *buf, int len);
e8574e
-int BIO_free(BIO *a);
b01884
-
e8574e
-/* openssl/asn1.h */
e8574e
-typedef struct ASN1_ENCODING_st {
e8574e
-    unsigned char *enc;         /* DER encoding */
e8574e
-    long len;                   /* Length of encoding */
e8574e
-    int modified;               /* set to 1 if 'enc' is invalid */
e8574e
-} ASN1_ENCODING;
b01884
-
e8574e
-/* openssl/evp.h */
e8574e
-typedef ... EVP_PKEY;
b01884
-
e8574e
-void EVP_PKEY_free(EVP_PKEY *pkey);
b01884
-
e8574e
-/* openssl/x509.h */
e8574e
-typedef ... ASN1_INTEGER;
e8574e
-typedef ... ASN1_BIT_STRING;
e8574e
-typedef ... ASN1_OBJECT;
e8574e
-typedef ... X509;
e8574e
-typedef ... X509_CRL;
e8574e
-typedef ... X509_NAME;
e8574e
-typedef ... X509_PUBKEY;
e8574e
-typedef ... ipa_STACK_OF_X509_ATTRIBUTE;
b01884
-
e8574e
-typedef struct X509_req_info_st {
e8574e
-    ASN1_ENCODING enc;
e8574e
-    ASN1_INTEGER *version;
e8574e
-    X509_NAME *subject;
e8574e
-    X509_PUBKEY *pubkey;
e8574e
-    /*  d=2 hl=2 l=  0 cons: cont: 00 */
e8574e
-    ipa_STACK_OF_X509_ATTRIBUTE *attributes; /* [ 0 ] */
e8574e
-} X509_REQ_INFO;
e8574e
-''')
e8574e
-
e8574e
-# since OpenSSL 1.1.0 req_info field is no longer pointer to X509_REQ_INFO
e8574e
-if _openssl_version >= 0x10100000 and not LIBRESSL:
e8574e
-    _ffi.cdef('''
e8574e
-    typedef struct X509_req_st {
e8574e
-        X509_REQ_INFO req_info;
e8574e
-    } X509_REQ;
e8574e
-    ''')
e8574e
-else:
e8574e
-    _ffi.cdef('''
e8574e
-    typedef struct X509_req_st {
e8574e
-        X509_REQ_INFO *req_info;
e8574e
-    } X509_REQ;
e8574e
-    ''')
b01884
-
e8574e
-_ffi.cdef('''
e8574e
-X509_REQ *X509_REQ_new(void);
e8574e
-void X509_REQ_free(X509_REQ *);
e8574e
-EVP_PKEY *d2i_PUBKEY_bio(BIO *bp, EVP_PKEY **a);
e8574e
-int X509_REQ_set_pubkey(X509_REQ *x, EVP_PKEY *pkey);
e8574e
-int X509_NAME_add_entry_by_OBJ(X509_NAME *name, const ASN1_OBJECT *obj, int type,
e8574e
-                               const unsigned char *bytes, int len, int loc,
e8574e
-                               int set);
e8574e
-int X509_NAME_entry_count(X509_NAME *name);
e8574e
-int i2d_X509_REQ_INFO(X509_REQ_INFO *a, unsigned char **out);
b01884
-
e8574e
-/* openssl/objects.h */
e8574e
-ASN1_OBJECT *OBJ_txt2obj(const char *s, int no_name);
b01884
-
e8574e
-/* openssl/x509v3.h */
e8574e
-typedef ... X509V3_CONF_METHOD;
b01884
-
e8574e
-typedef struct v3_ext_ctx {
e8574e
-    int flags;
e8574e
-    X509 *issuer_cert;
e8574e
-    X509 *subject_cert;
e8574e
-    X509_REQ *subject_req;
e8574e
-    X509_CRL *crl;
e8574e
-    X509V3_CONF_METHOD *db_meth;
e8574e
-    void *db;
e8574e
-} X509V3_CTX;
b01884
-
e8574e
-void X509V3_set_ctx(X509V3_CTX *ctx, X509 *issuer, X509 *subject,
e8574e
-                    X509_REQ *req, X509_CRL *crl, int flags);
e8574e
-void X509V3_set_nconf(X509V3_CTX *ctx, CONF *conf);
e8574e
-int X509V3_EXT_REQ_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section,
e8574e
-                             X509_REQ *req);
b01884
-
e8574e
-/* openssl/x509v3.h */
e8574e
-unsigned long ERR_get_error(void);
e8574e
-char *ERR_error_string(unsigned long e, char *buf);
e8574e
-''')  # noqa: E501
b01884
-
e8574e
-NULL = _ffi.NULL
e8574e
-# openssl/conf.h
e8574e
-NCONF_new = _libcrypto.NCONF_new
e8574e
-NCONF_free = _libcrypto.NCONF_free
e8574e
-NCONF_load_bio = _libcrypto.NCONF_load_bio
e8574e
-NCONF_get_section = _libcrypto.NCONF_get_section
e8574e
-NCONF_get_string = _libcrypto.NCONF_get_string
b01884
-
e8574e
-# openssl/stack.h
e8574e
-try:
e8574e
-    sk_num = _libcrypto.OPENSSL_sk_num
e8574e
-    sk_value = _libcrypto.OPENSSL_sk_value
e8574e
-except AttributeError:
e8574e
-    sk_num = _libcrypto.sk_num
e8574e
-    sk_value = _libcrypto.sk_value
b01884
-
b01884
-
e8574e
-def sk_CONF_VALUE_num(sk):
e8574e
-    return sk_num(_ffi.cast("_STACK *", sk))
b01884
-
b01884
-
e8574e
-def sk_CONF_VALUE_value(sk, i):
e8574e
-    return _ffi.cast("CONF_VALUE *", sk_value(_ffi.cast("_STACK *", sk), i))
b01884
-
b01884
-
e8574e
-# openssl/bio.h
e8574e
-BIO_new_mem_buf = _libcrypto.BIO_new_mem_buf
e8574e
-BIO_free = _libcrypto.BIO_free
b01884
-
e8574e
-# openssl/x509.h
e8574e
-X509_REQ_new = _libcrypto.X509_REQ_new
e8574e
-X509_REQ_free = _libcrypto.X509_REQ_free
e8574e
-X509_REQ_set_pubkey = _libcrypto.X509_REQ_set_pubkey
e8574e
-d2i_PUBKEY_bio = _libcrypto.d2i_PUBKEY_bio
e8574e
-i2d_X509_REQ_INFO = _libcrypto.i2d_X509_REQ_INFO
e8574e
-X509_NAME_add_entry_by_OBJ = _libcrypto.X509_NAME_add_entry_by_OBJ
e8574e
-X509_NAME_entry_count = _libcrypto.X509_NAME_entry_count
b01884
-
b01884
-
e8574e
-def X509_REQ_get_subject_name(req):
e8574e
-    return req.req_info.subject
b01884
-
b01884
-
e8574e
-# openssl/objects.h
e8574e
-OBJ_txt2obj = _libcrypto.OBJ_txt2obj
b01884
-
e8574e
-# openssl/evp.h
e8574e
-EVP_PKEY_free = _libcrypto.EVP_PKEY_free
b01884
-
e8574e
-# openssl/asn1.h
e8574e
-MBSTRING_UTF8 = 0x1000
b01884
-
e8574e
-# openssl/x509v3.h
e8574e
-X509V3_set_ctx = _libcrypto.X509V3_set_ctx
e8574e
-X509V3_set_nconf = _libcrypto.X509V3_set_nconf
e8574e
-X509V3_EXT_REQ_add_nconf = _libcrypto.X509V3_EXT_REQ_add_nconf
b01884
-
e8574e
-# openssl/err.h
e8574e
-ERR_get_error = _libcrypto.ERR_get_error
e8574e
-ERR_error_string = _libcrypto.ERR_error_string
b01884
-
b01884
-
e8574e
-def _raise_openssl_errors():
e8574e
-    msgs = []
b01884
-
e8574e
-    code = ERR_get_error()
e8574e
-    while code != 0:
e8574e
-        msg = _ffi.string(ERR_error_string(code, NULL))
e8574e
-        try:
e8574e
-            strmsg = msg.decode('utf-8')
e8574e
-        except UnicodeDecodeError:
e8574e
-            strmsg = repr(msg)
e8574e
-        msgs.append(strmsg)
e8574e
-        code = ERR_get_error()
b01884
-
e8574e
-    raise errors.CSRTemplateError(reason='\n'.join(msgs))
b01884
-
b01884
-
e8574e
-def _parse_dn_section(subj, dn_sk):
e8574e
-    for i in range(sk_CONF_VALUE_num(dn_sk)):
e8574e
-        v = sk_CONF_VALUE_value(dn_sk, i)
e8574e
-        rdn_type = _ffi.string(v.name)
b01884
-
e8574e
-        # Skip past any leading X. X: X, etc to allow for multiple instances
e8574e
-        for idx, c in enumerate(rdn_type):
e8574e
-            if c in b':,.':
e8574e
-                if idx+1 < len(rdn_type):
e8574e
-                    rdn_type = rdn_type[idx+1:]
e8574e
-                break
e8574e
-        if rdn_type.startswith(b'+'):
e8574e
-            rdn_type = rdn_type[1:]
e8574e
-            mval = -1
e8574e
-        else:
e8574e
-            mval = 0
b01884
-
e8574e
-        # convert rdn_type to an OID
e8574e
-        #
e8574e
-        # OpenSSL is fussy about the case of the string.  For example,
e8574e
-        # lower-case 'o' (for "organization name") is not recognised.
e8574e
-        # Therefore, try to convert the given string into an OID.  If
e8574e
-        # that fails, convert it upper case and try again.
e8574e
-        #
e8574e
-        oid = OBJ_txt2obj(rdn_type, 0)
e8574e
-        if oid == NULL:
e8574e
-            oid = OBJ_txt2obj(rdn_type.upper(), 0)
e8574e
-        if oid == NULL:
e8574e
-            raise errors.CSRTemplateError(
e8574e
-                reason='unrecognised attribute type: {}'
e8574e
-                .format(rdn_type.decode('utf-8')))
b01884
-
e8574e
-        if not X509_NAME_add_entry_by_OBJ(
e8574e
-                subj, oid, MBSTRING_UTF8,
e8574e
-                _ffi.cast("unsigned char *", v.value), -1, -1, mval):
e8574e
-            _raise_openssl_errors()
b01884
-
e8574e
-    if not X509_NAME_entry_count(subj):
e8574e
-        raise errors.CSRTemplateError(
e8574e
-            reason='error, subject in config file is empty')
b01884
-
b01884
-
e8574e
-def build_requestinfo(config, public_key_info):
e8574e
-    '''
e8574e
-    Return a cffi buffer containing a DER-encoded CertificationRequestInfo.
b01884
-
e8574e
-    The returned object implements the buffer protocol.
b01884
-
e8574e
-    '''
e8574e
-    reqdata = NULL
e8574e
-    req = NULL
e8574e
-    nconf_bio = NULL
e8574e
-    pubkey_bio = NULL
e8574e
-    pubkey = NULL
b01884
-
e8574e
-    try:
e8574e
-        reqdata = NCONF_new(NULL)
e8574e
-        if reqdata == NULL:
e8574e
-            _raise_openssl_errors()
b01884
-
e8574e
-        nconf_bio = BIO_new_mem_buf(config, len(config))
e8574e
-        errorline = _ffi.new('long[1]', [-1])
e8574e
-        i = NCONF_load_bio(reqdata, nconf_bio, errorline)
e8574e
-        if i < 0:
e8574e
-            if errorline[0] < 0:
e8574e
-                raise errors.CSRTemplateError(reason="Can't load config file")
e8574e
-            else:
e8574e
-                raise errors.CSRTemplateError(
e8574e
-                    reason='Error on line %d of config file' % errorline[0])
b01884
-
e8574e
-        dn_sect = NCONF_get_string(reqdata, b'req', b'distinguished_name')
e8574e
-        if dn_sect == NULL:
e8574e
-            raise errors.CSRTemplateError(
e8574e
-                reason='Unable to find "distinguished_name" key in config')
b01884
-
e8574e
-        dn_sk = NCONF_get_section(reqdata, dn_sect)
e8574e
-        if dn_sk == NULL:
e8574e
-            raise errors.CSRTemplateError(
e8574e
-                reason='Unable to find "%s" section in config' %
e8574e
-                _ffi.string(dn_sect))
b01884
-
e8574e
-        pubkey_bio = BIO_new_mem_buf(public_key_info, len(public_key_info))
e8574e
-        pubkey = d2i_PUBKEY_bio(pubkey_bio, NULL)
e8574e
-        if pubkey == NULL:
e8574e
-            _raise_openssl_errors()
b01884
-
e8574e
-        req = X509_REQ_new()
e8574e
-        if req == NULL:
e8574e
-            _raise_openssl_errors()
b01884
-
e8574e
-        subject = X509_REQ_get_subject_name(req)
b01884
-
e8574e
-        _parse_dn_section(subject, dn_sk)
b01884
-
e8574e
-        if not X509_REQ_set_pubkey(req, pubkey):
e8574e
-            _raise_openssl_errors()
b01884
-
e8574e
-        ext_ctx = _ffi.new("X509V3_CTX[1]")
e8574e
-        X509V3_set_ctx(ext_ctx, NULL, NULL, req, NULL, 0)
e8574e
-        X509V3_set_nconf(ext_ctx, reqdata)
b01884
-
e8574e
-        extn_section = NCONF_get_string(reqdata, b"req", b"req_extensions")
e8574e
-        if extn_section != NULL:
e8574e
-            if not X509V3_EXT_REQ_add_nconf(
e8574e
-                    reqdata, ext_ctx, extn_section, req):
e8574e
-                _raise_openssl_errors()
b01884
-
e8574e
-        if _openssl_version < 0x10100000 or LIBRESSL:
e8574e
-            der_len = i2d_X509_REQ_INFO(req.req_info, NULL)
e8574e
-        else:
e8574e
-            req_info = _ffi.new("X509_REQ_INFO *", req.req_info)
e8574e
-            der_len = i2d_X509_REQ_INFO(req_info, NULL)
e8574e
-            req.req_info = req_info[0]
e8574e
-        if der_len < 0:
e8574e
-            _raise_openssl_errors()
b01884
-
e8574e
-        der_buf = _ffi.new("unsigned char[%d]" % der_len)
e8574e
-        der_out = _ffi.new("unsigned char **", der_buf)
e8574e
-        if _openssl_version < 0x10100000 or LIBRESSL:
e8574e
-            der_len = i2d_X509_REQ_INFO(req.req_info, der_out)
e8574e
-        else:
e8574e
-            der_len = i2d_X509_REQ_INFO(req_info, der_out)
e8574e
-            req.req_info = req_info[0]
e8574e
-        if der_len < 0:
e8574e
-            _raise_openssl_errors()
b01884
-
e8574e
-        return _ffi.buffer(der_buf, der_len)
b01884
-
e8574e
-    finally:
e8574e
-        if reqdata != NULL:
e8574e
-            NCONF_free(reqdata)
e8574e
-        if req != NULL:
e8574e
-            X509_REQ_free(req)
e8574e
-        if nconf_bio != NULL:
e8574e
-            BIO_free(nconf_bio)
e8574e
-        if pubkey_bio != NULL:
e8574e
-            BIO_free(pubkey_bio)
e8574e
-        if pubkey != NULL:
e8574e
-            EVP_PKEY_free(pubkey)
e8574e
diff -urN freeipa-4.8.0/ipaclient/csrgen.py freeipa-4.8.0.removed_csrgen/ipaclient/csrgen.py
e8574e
--- freeipa-4.8.0/ipaclient/csrgen.py	2019-07-03 08:42:41.811540288 +0200
e8574e
+++ freeipa-4.8.0.removed_csrgen/ipaclient/csrgen.py	1970-01-01 01:00:00.000000000 +0100
e8574e
@@ -1,488 +0,0 @@
e8574e
-#
e8574e
-# Copyright (C) 2016  FreeIPA Contributors see COPYING for license
e8574e
-#
b01884
-
e8574e
-import base64
e8574e
-import collections
e8574e
-import errno
e8574e
-import json
e8574e
-import logging
e8574e
-import os
e8574e
-import os.path
e8574e
-import pipes
e8574e
-import subprocess
e8574e
-import traceback
e8574e
-import codecs
b01884
-
e8574e
-import pkg_resources
b01884
-
e8574e
-from cryptography.hazmat.backends import default_backend
e8574e
-from cryptography.hazmat.primitives.asymmetric import padding
e8574e
-from cryptography.hazmat.primitives import hashes
e8574e
-from cryptography.hazmat.primitives.serialization import (
e8574e
-    load_pem_private_key, Encoding, PublicFormat)
e8574e
-from cryptography.x509 import load_pem_x509_certificate
e8574e
-import jinja2
e8574e
-import jinja2.ext
e8574e
-import jinja2.sandbox
e8574e
-from pyasn1.codec.der import decoder, encoder
e8574e
-from pyasn1.type import univ
e8574e
-from pyasn1_modules import rfc2314
e8574e
-import six
b01884
-
e8574e
-from ipalib import api
e8574e
-from ipalib import errors
e8574e
-from ipalib.text import _
b01884
-
e8574e
-if six.PY3:
e8574e
-    unicode = str
b01884
-
e8574e
-__doc__ = _("""
e8574e
-Routines for constructing certificate signing requests using IPA data and
e8574e
-stored templates.
e8574e
-""")
b01884
-
e8574e
-logger = logging.getLogger(__name__)
b01884
-
b01884
-
e8574e
-class IndexableUndefined(jinja2.Undefined):
e8574e
-    def __getitem__(self, key):
e8574e
-        return jinja2.Undefined(
e8574e
-            hint=self._undefined_hint, obj=self._undefined_obj,
e8574e
-            name=self._undefined_name, exc=self._undefined_exception)
b01884
-
b01884
-
e8574e
-class IPAExtension(jinja2.ext.Extension):
e8574e
-    """Jinja2 extension providing useful features for CSR generation rules."""
b01884
-
e8574e
-    def __init__(self, environment):
e8574e
-        super(IPAExtension, self).__init__(environment)
b01884
-
e8574e
-        environment.filters.update(
e8574e
-            quote=self.quote,
e8574e
-            required=self.required,
e8574e
-        )
b01884
-
e8574e
-    def quote(self, data):
e8574e
-        return pipes.quote(data)
b01884
-
e8574e
-    def required(self, data, name):
e8574e
-        if not data:
e8574e
-            raise errors.CSRTemplateError(
e8574e
-                reason=_(
e8574e
-                    'Required CSR generation rule %(name)s is missing data') %
e8574e
-                {'name': name})
e8574e
-        return data
b01884
-
b01884
-
e8574e
-class Formatter:
e8574e
-    """
e8574e
-    Class for processing a set of CSR generation rules into a template.
e8574e
-
e8574e
-    The template can be rendered with user and database data to produce a
e8574e
-    config, which specifies how to build a CSR.
e8574e
-
e8574e
-    Subclasses of Formatter should set the value of base_template_name to the
e8574e
-    filename of a base template with spaces for the processed rules.
e8574e
-    Additionally, they should override the _get_template_params method to
e8574e
-    produce the correct output for the base template.
e8574e
-    """
e8574e
-    base_template_name = None
e8574e
-
e8574e
-    def __init__(self, csr_data_dir=None):
e8574e
-        # chain loaders:
e8574e
-        # 1) csr_data_dir/templates
e8574e
-        # 2) /etc/ipa/csrgen/templates
e8574e
-        # 3) ipaclient/csrgen/templates
e8574e
-        loaders = []
e8574e
-        if csr_data_dir is not None:
e8574e
-            loaders.append(jinja2.FileSystemLoader(
e8574e
-                os.path.join(csr_data_dir, 'templates'))
e8574e
-            )
e8574e
-        loaders.append(jinja2.FileSystemLoader(
e8574e
-            os.path.join(api.env.confdir, 'csrgen/templates'))
b01884
-        )
e8574e
-        loaders.append(jinja2.PackageLoader('ipaclient', 'csrgen/templates'))
b01884
-
e8574e
-        self.jinja2 = jinja2.sandbox.SandboxedEnvironment(
e8574e
-            loader=jinja2.ChoiceLoader(loaders),
e8574e
-            extensions=[jinja2.ext.ExprStmtExtension, IPAExtension],
e8574e
-            keep_trailing_newline=True, undefined=IndexableUndefined)
b01884
-
e8574e
-        self.passthrough_globals = {}
b01884
-
e8574e
-    def _define_passthrough(self, call):
e8574e
-        """Some macros are meant to be interpreted during the final render, not
e8574e
-        when data rules are interpolated into syntax rules. This method allows
e8574e
-        those macros to be registered so that calls to them are passed through
e8574e
-        to the prepared rule rather than interpreted.
e8574e
-        """
b01884
-
e8574e
-        def passthrough(caller):
e8574e
-            return u'{%% call %s() %%}%s{%% endcall %%}' % (call, caller())
b01884
-
e8574e
-        parts = call.split('.')
e8574e
-        current_level = self.passthrough_globals
e8574e
-        for part in parts[:-1]:
e8574e
-            if part not in current_level:
e8574e
-                current_level[part] = {}
e8574e
-            current_level = current_level[part]
e8574e
-        current_level[parts[-1]] = passthrough
b01884
-
e8574e
-    def build_template(self, rules):
e8574e
-        """
e8574e
-        Construct a template that can produce CSR generator strings.
b01884
-
e8574e
-        :param rules: list of FieldMapping to use to populate the template.
b01884
-
e8574e
-        :returns: jinja2.Template that can be rendered to produce the CSR data.
e8574e
-        """
e8574e
-        syntax_rules = []
e8574e
-        for field_mapping in rules:
e8574e
-            data_rules_prepared = [
e8574e
-                self._prepare_data_rule(rule)
e8574e
-                for rule in field_mapping.data_rules]
b01884
-
e8574e
-            data_sources = []
e8574e
-            for xrule in field_mapping.data_rules:
e8574e
-                data_source = xrule.options.get('data_source')
e8574e
-                if data_source:
e8574e
-                    data_sources.append(data_source)
b01884
-
e8574e
-            syntax_rules.append(self._prepare_syntax_rule(
e8574e
-                field_mapping.syntax_rule, data_rules_prepared,
e8574e
-                field_mapping.description, data_sources))
e8574e
-
e8574e
-        template_params = self._get_template_params(syntax_rules)
e8574e
-        base_template = self.jinja2.get_template(
e8574e
-            self.base_template_name, globals=self.passthrough_globals)
e8574e
-
e8574e
-        try:
e8574e
-            combined_template_source = base_template.render(**template_params)
e8574e
-        except jinja2.UndefinedError:
e8574e
-            logger.debug(traceback.format_exc())
e8574e
-            raise errors.CSRTemplateError(reason=_(
e8574e
-                'Template error when formatting certificate data'))
e8574e
-
e8574e
-        logger.debug(
e8574e
-            'Formatting with template: %s', combined_template_source)
e8574e
-        combined_template = self.jinja2.from_string(combined_template_source)
b01884
-
e8574e
-        return combined_template
b01884
-
e8574e
-    def _wrap_conditional(self, rule, condition):
e8574e
-        rule = '{%% if %s %%}%s{%% endif %%}' % (condition, rule)
e8574e
-        return rule
b01884
-
e8574e
-    def _wrap_required(self, rule, description):
e8574e
-        template = '{%% filter required("%s") %%}%s{%% endfilter %%}' % (
e8574e
-            description, rule)
b01884
-
e8574e
-        return template
b01884
-
e8574e
-    def _prepare_data_rule(self, data_rule):
e8574e
-        template = data_rule.template
b01884
-
e8574e
-        data_source = data_rule.options.get('data_source')
e8574e
-        if data_source:
e8574e
-            template = self._wrap_conditional(template, data_source)
b01884
-
e8574e
-        return template
b01884
-
e8574e
-    def _prepare_syntax_rule(
e8574e
-            self, syntax_rule, data_rules, description, data_sources):
e8574e
-        logger.debug('Syntax rule template: %s', syntax_rule.template)
e8574e
-        template = self.jinja2.from_string(
e8574e
-            syntax_rule.template, globals=self.passthrough_globals)
e8574e
-        is_required = syntax_rule.options.get('required', False)
e8574e
-        try:
e8574e
-            prepared_template = template.render(datarules=data_rules)
e8574e
-        except jinja2.UndefinedError:
e8574e
-            logger.debug(traceback.format_exc())
e8574e
-            raise errors.CSRTemplateError(reason=_(
e8574e
-                'Template error when formatting certificate data'))
b01884
-
e8574e
-        if data_sources:
e8574e
-            combinator = ' %s ' % syntax_rule.options.get(
e8574e
-                'data_source_combinator', 'or')
e8574e
-            condition = combinator.join(data_sources)
e8574e
-            prepared_template = self._wrap_conditional(
e8574e
-                prepared_template, condition)
b01884
-
e8574e
-        if is_required:
e8574e
-            prepared_template = self._wrap_required(
e8574e
-                prepared_template, description)
b01884
-
e8574e
-        return prepared_template
b01884
-
e8574e
-    def _get_template_params(self, syntax_rules):
e8574e
-        """
e8574e
-        Package the syntax rules into fields expected by the base template.
b01884
-
e8574e
-        :param syntax_rules: list of prepared syntax rules to be included in
e8574e
-            the template.
b01884
-
e8574e
-        :returns: dict of values needed to render the base template.
e8574e
-        """
e8574e
-        raise NotImplementedError('Formatter class must be subclassed')
b01884
-
b01884
-
e8574e
-class OpenSSLFormatter(Formatter):
e8574e
-    """Formatter class generating the openssl config-file format."""
b01884
-
e8574e
-    base_template_name = 'openssl_base.tmpl'
e8574e
-
e8574e
-    # Syntax rules are wrapped in this data structure, to keep track of whether
e8574e
-    # each goes in the extension or the root section
e8574e
-    SyntaxRule = collections.namedtuple(
e8574e
-        'SyntaxRule', ['template', 'is_extension'])
b01884
-
e8574e
-    def __init__(self, *args, **kwargs):
e8574e
-        super(OpenSSLFormatter, self).__init__(*args, **kwargs)
e8574e
-        self._define_passthrough('openssl.section')
b01884
-
e8574e
-    def _get_template_params(self, syntax_rules):
e8574e
-        parameters = [rule.template for rule in syntax_rules
e8574e
-                      if not rule.is_extension]
e8574e
-        extensions = [rule.template for rule in syntax_rules
e8574e
-                      if rule.is_extension]
b01884
-
e8574e
-        return {'parameters': parameters, 'extensions': extensions}
b01884
-
e8574e
-    def _prepare_syntax_rule(
e8574e
-            self, syntax_rule, data_rules, description, data_sources):
e8574e
-        """Overrides method to pull out whether rule is an extension or not."""
e8574e
-        prepared_template = super(OpenSSLFormatter, self)._prepare_syntax_rule(
e8574e
-            syntax_rule, data_rules, description, data_sources)
e8574e
-        is_extension = syntax_rule.options.get('extension', False)
e8574e
-        return self.SyntaxRule(prepared_template, is_extension)
b01884
-
b01884
-
e8574e
-class FieldMapping:
e8574e
-    """Representation of the rules needed to construct a complete cert field.
b01884
-
e8574e
-    Attributes:
e8574e
-        description: str, a name or description of this field, to be used in
e8574e
-            messages
e8574e
-        syntax_rule: Rule, the rule defining the syntax of this field
e8574e
-        data_rules: list of Rule, the rules that produce data to be stored in
e8574e
-            this field
e8574e
-    """
e8574e
-    __slots__ = ['description', 'syntax_rule', 'data_rules']
b01884
-
e8574e
-    def __init__(self, description, syntax_rule, data_rules):
e8574e
-        self.description = description
e8574e
-        self.syntax_rule = syntax_rule
e8574e
-        self.data_rules = data_rules
b01884
-
b01884
-
e8574e
-class Rule:
e8574e
-    __slots__ = ['name', 'template', 'options']
b01884
-
e8574e
-    def __init__(self, name, template, options):
e8574e
-        self.name = name
e8574e
-        self.template = template
e8574e
-        self.options = options
b01884
-
b01884
-
e8574e
-class RuleProvider:
e8574e
-    def rules_for_profile(self, profile_id):
e8574e
-        """
e8574e
-        Return the rules needed to build a CSR using the given profile.
b01884
-
e8574e
-        :param profile_id: str, name of the CSR generation profile to use
b01884
-
e8574e
-        :returns: list of FieldMapping, filled out with the appropriate rules
e8574e
-        """
e8574e
-        raise NotImplementedError('RuleProvider class must be subclassed')
b01884
-
b01884
-
e8574e
-class FileRuleProvider(RuleProvider):
e8574e
-    def __init__(self, csr_data_dir=None):
e8574e
-        self.rules = {}
e8574e
-        self._csrgen_data_dirs = []
e8574e
-        if csr_data_dir is not None:
e8574e
-            self._csrgen_data_dirs.append(csr_data_dir)
e8574e
-        self._csrgen_data_dirs.append(
e8574e
-            os.path.join(api.env.confdir, 'csrgen')
e8574e
-        )
e8574e
-        self._csrgen_data_dirs.append(
e8574e
-            pkg_resources.resource_filename('ipaclient', 'csrgen')
e8574e
-        )
b01884
-
e8574e
-    def _open(self, subdir, filename):
e8574e
-        for data_dir in self._csrgen_data_dirs:
e8574e
-            path = os.path.join(data_dir, subdir, filename)
e8574e
-            try:
e8574e
-                return open(path)
e8574e
-            except IOError as e:
e8574e
-                if e.errno != errno.ENOENT:
e8574e
-                    raise
e8574e
-        raise IOError(
e8574e
-            errno.ENOENT,
e8574e
-            "'{}' not found in {}".format(
e8574e
-                os.path.join(subdir, filename),
e8574e
-                ", ".join(self._csrgen_data_dirs)
e8574e
-            )
e8574e
-        )
b01884
-
e8574e
-    def _rule(self, rule_name):
e8574e
-        if rule_name not in self.rules:
e8574e
-            try:
e8574e
-                with self._open('rules', '%s.json' % rule_name) as f:
e8574e
-                    ruleconf = json.load(f)
e8574e
-            except IOError:
e8574e
-                raise errors.NotFound(
e8574e
-                    reason=_('No generation rule %(rulename)s found.') %
e8574e
-                    {'rulename': rule_name})
b01884
-
e8574e
-            try:
e8574e
-                rule = ruleconf['rule']
e8574e
-            except KeyError:
e8574e
-                raise errors.EmptyResult(
e8574e
-                    reason=_('Generation rule "%(rulename)s" is missing the'
e8574e
-                             ' "rule" key') % {'rulename': rule_name})
b01884
-
e8574e
-            options = ruleconf.get('options', {})
b01884
-
e8574e
-            self.rules[rule_name] = Rule(
e8574e
-                rule_name, rule['template'], options)
b01884
-
e8574e
-        return self.rules[rule_name]
b01884
-
e8574e
-    def rules_for_profile(self, profile_id):
e8574e
-        try:
e8574e
-            with self._open('profiles', '%s.json' % profile_id) as f:
e8574e
-                profile = json.load(f)
e8574e
-        except IOError:
e8574e
-            raise errors.NotFound(
e8574e
-                reason=_('No CSR generation rules are defined for profile'
e8574e
-                         ' %(profile_id)s') % {'profile_id': profile_id})
b01884
-
e8574e
-        field_mappings = []
e8574e
-        for field in profile:
e8574e
-            syntax_rule = self._rule(field['syntax'])
e8574e
-            data_rules = [self._rule(name) for name in field['data']]
e8574e
-            field_mappings.append(FieldMapping(
e8574e
-                syntax_rule.name, syntax_rule, data_rules))
e8574e
-        return field_mappings
b01884
-
b01884
-
e8574e
-class CSRGenerator:
e8574e
-    def __init__(self, rule_provider, formatter_class=OpenSSLFormatter):
e8574e
-        self.rule_provider = rule_provider
e8574e
-        self.formatter = formatter_class()
b01884
-
e8574e
-    def csr_config(self, principal, config, profile_id):
e8574e
-        render_data = {'subject': principal, 'config': config}
b01884
-
e8574e
-        rules = self.rule_provider.rules_for_profile(profile_id)
e8574e
-        template = self.formatter.build_template(rules)
b01884
-
e8574e
-        try:
e8574e
-            config = template.render(render_data)
e8574e
-        except jinja2.UndefinedError:
e8574e
-            logger.debug(traceback.format_exc())
e8574e
-            raise errors.CSRTemplateError(reason=_(
e8574e
-                'Template error when formatting certificate data'))
b01884
-
e8574e
-        return config
b01884
-
b01884
-
e8574e
-class CSRLibraryAdaptor:
e8574e
-    def get_subject_public_key_info(self):
e8574e
-        raise NotImplementedError('Use a subclass of CSRLibraryAdaptor')
b01884
-
e8574e
-    def sign_csr(self, certification_request_info):
e8574e
-        """Sign a CertificationRequestInfo.
b01884
-
e8574e
-        :returns: bytes, a DER-encoded signed CSR.
e8574e
-        """
e8574e
-        raise NotImplementedError('Use a subclass of CSRLibraryAdaptor')
b01884
-
b01884
-
e8574e
-class OpenSSLAdaptor:
e8574e
-    def __init__(self, key=None, key_filename=None, password_filename=None):
e8574e
-        """
e8574e
-        Must provide either ``key_filename`` or ``key``.
b01884
-
e8574e
-        """
e8574e
-        if key_filename is not None:
e8574e
-            with open(key_filename, 'rb') as key_file:
e8574e
-                key_bytes = key_file.read()
b01884
-
e8574e
-            password = None
e8574e
-            if password_filename is not None:
e8574e
-                with open(password_filename, 'rb') as password_file:
e8574e
-                    password = password_file.read().strip()
b01884
-
e8574e
-            self._key = load_pem_private_key(
e8574e
-                key_bytes, password, default_backend())
b01884
-
e8574e
-        elif key is not None:
e8574e
-            self._key = key
b01884
-
e8574e
-        else:
e8574e
-            raise ValueError("Must provide 'key' or 'key_filename'")
b01884
-
e8574e
-    def key(self):
e8574e
-        return self._key
b01884
-
e8574e
-    def get_subject_public_key_info(self):
e8574e
-        pubkey_info = self.key().public_key().public_bytes(
e8574e
-            Encoding.DER, PublicFormat.SubjectPublicKeyInfo)
e8574e
-        return pubkey_info
b01884
-
e8574e
-    def sign_csr(self, certification_request_info):
e8574e
-        reqinfo = decoder.decode(
e8574e
-            certification_request_info, rfc2314.CertificationRequestInfo())[0]
e8574e
-        csr = rfc2314.CertificationRequest()
e8574e
-        csr.setComponentByName('certificationRequestInfo', reqinfo)
b01884
-
e8574e
-        algorithm = rfc2314.SignatureAlgorithmIdentifier()
e8574e
-        algorithm.setComponentByName(
e8574e
-            'algorithm', univ.ObjectIdentifier(
e8574e
-                '1.2.840.113549.1.1.11'))  # sha256WithRSAEncryption
e8574e
-        csr.setComponentByName('signatureAlgorithm', algorithm)
b01884
-
e8574e
-        signature = self.key().sign(
e8574e
-            certification_request_info,
e8574e
-            padding.PKCS1v15(),
e8574e
-            hashes.SHA256()
e8574e
-        )
e8574e
-        asn1sig = univ.BitString("'{sig}'H".format(
e8574e
-                                    sig=codecs.encode(signature, 'hex')
e8574e
-                                    .decode('ascii'))
e8574e
-                                 )
e8574e
-        csr.setComponentByName('signature', asn1sig)
e8574e
-        return encoder.encode(csr)
b01884
-
b01884
-
e8574e
-class NSSAdaptor:
e8574e
-    def __init__(self, database, password_filename):
e8574e
-        self.database = database
e8574e
-        self.password_filename = password_filename
e8574e
-        self.nickname = base64.b32encode(os.urandom(40))
b01884
-
e8574e
-    def get_subject_public_key_info(self):
e8574e
-        temp_cn = base64.b32encode(os.urandom(40)).decode('ascii')
b01884
-
e8574e
-        password_args = []
e8574e
-        if self.password_filename is not None:
e8574e
-            password_args = ['-f', self.password_filename]
b01884
-
e8574e
-        subprocess.check_call(
e8574e
-            ['certutil', '-S', '-n', self.nickname, '-s', 'CN=%s' % temp_cn,
e8574e
-             '-x', '-t', ',,', '-d', self.database] + password_args)
e8574e
-        cert_pem = subprocess.check_output(
e8574e
-            ['certutil', '-L', '-n', self.nickname, '-a',
e8574e
-             '-d', self.database] + password_args)
b01884
-
e8574e
-        cert = load_pem_x509_certificate(cert_pem, default_backend())
e8574e
-        pubkey_info = cert.public_key().public_bytes(
e8574e
-            Encoding.DER, PublicFormat.SubjectPublicKeyInfo)
b01884
-
e8574e
-        return pubkey_info
b01884
-
e8574e
-    def sign_csr(self, certification_request_info):
e8574e
-        raise NotImplementedError('NSS is not yet supported')
e8574e
diff -urN freeipa-4.8.0/ipaclient/plugins/cert.py freeipa-4.8.0.removed_csrgen/ipaclient/plugins/cert.py
e8574e
--- freeipa-4.8.0/ipaclient/plugins/cert.py	2019-07-03 08:42:41.978537802 +0200
e8574e
+++ freeipa-4.8.0.removed_csrgen/ipaclient/plugins/cert.py	2019-07-03 13:24:38.477222594 +0200
b01884
@@ -21,8 +21,6 @@
b01884
 
b01884
 import base64
b01884
 
b01884
-import six
b01884
-
b01884
 from ipaclient.frontend import MethodOverride
b01884
 from ipalib import errors
b01884
 from ipalib import x509
e8574e
@@ -31,9 +29,6 @@
b01884
 from ipalib.plugable import Registry
b01884
 from ipalib.text import _
b01884
 
b01884
-if six.PY3:
b01884
-    unicode = str
b01884
-
b01884
 register = Registry()
b01884
 
b01884
 
e8574e
@@ -73,87 +68,12 @@
b01884
 
b01884
 @register(override=True, no_fail=True)
b01884
 class cert_request(CertRetrieveOverride):
b01884
-    takes_options = CertRetrieveOverride.takes_options + (
b01884
-        Str(
b01884
-            'database?',
b01884
-            label=_('Path to NSS database'),
b01884
-            doc=_('Path to NSS database to use for private key'),
b01884
-        ),
b01884
-        Str(
b01884
-            'private_key?',
b01884
-            label=_('Path to private key file'),
b01884
-            doc=_('Path to PEM file containing a private key'),
b01884
-        ),
b01884
-        Str(
b01884
-            'password_file?',
b01884
-            label=_(
b01884
-                'File containing a password for the private key or database'),
b01884
-        ),
b01884
-        Str(
b01884
-            'csr_profile_id?',
b01884
-            label=_('Name of CSR generation profile (if not the same as'
b01884
-                    ' profile_id)'),
b01884
-        ),
b01884
-    )
b01884
-
b01884
     def get_args(self):
b01884
         for arg in super(cert_request, self).get_args():
b01884
             if arg.name == 'csr':
b01884
                 arg = arg.clone_retype(arg.name, File, required=False)
b01884
             yield arg
b01884
 
b01884
-    def forward(self, csr=None, **options):
b01884
-        database = options.pop('database', None)
b01884
-        private_key = options.pop('private_key', None)
b01884
-        csr_profile_id = options.pop('csr_profile_id', None)
b01884
-        password_file = options.pop('password_file', None)
b01884
-
b01884
-        if csr is None:
b01884
-            # Deferred import, ipaclient.csrgen is expensive to load.
b01884
-            # see https://pagure.io/freeipa/issue/7484
b01884
-            from ipaclient import csrgen
b01884
-
b01884
-            if database:
b01884
-                adaptor = csrgen.NSSAdaptor(database, password_file)
b01884
-            elif private_key:
b01884
-                adaptor = csrgen.OpenSSLAdaptor(
b01884
-                    key_filename=private_key, password_filename=password_file)
b01884
-            else:
b01884
-                raise errors.InvocationError(
b01884
-                    message=u"One of 'database' or 'private_key' is required")
b01884
-
b01884
-            pubkey_info = adaptor.get_subject_public_key_info()
b01884
-            pubkey_info_b64 = base64.b64encode(pubkey_info)
b01884
-
b01884
-            # If csr_profile_id is passed, that takes precedence.
b01884
-            # Otherwise, use profile_id. If neither are passed, the default
b01884
-            # in cert_get_requestdata will be used.
b01884
-            profile_id = csr_profile_id
b01884
-            if profile_id is None:
b01884
-                profile_id = options.get('profile_id')
b01884
-
b01884
-            response = self.api.Command.cert_get_requestdata(
b01884
-                profile_id=profile_id,
b01884
-                principal=options.get('principal'),
b01884
-                public_key_info=pubkey_info_b64)
b01884
-
b01884
-            req_info_b64 = response['result']['request_info']
b01884
-            req_info = base64.b64decode(req_info_b64)
b01884
-
b01884
-            csr = adaptor.sign_csr(req_info)
b01884
-
b01884
-            if not csr:
b01884
-                raise errors.CertificateOperationError(
b01884
-                    error=(_('Generated CSR was empty')))
b01884
-
b01884
-        else:
b01884
-            if database is not None or private_key is not None:
b01884
-                raise errors.MutuallyExclusiveError(reason=_(
b01884
-                    "Options 'database' and 'private_key' are not compatible"
b01884
-                    " with 'csr'"))
b01884
-
b01884
-        return super(cert_request, self).forward(csr, **options)
b01884
-
b01884
 
b01884
 @register(override=True, no_fail=True)
b01884
 class cert_show(CertRetrieveOverride):
e8574e
diff -urN freeipa-4.8.0/ipaclient/plugins/cert.py.orig freeipa-4.8.0.removed_csrgen/ipaclient/plugins/cert.py.orig
e8574e
--- freeipa-4.8.0/ipaclient/plugins/cert.py.orig	1970-01-01 01:00:00.000000000 +0100
e8574e
+++ freeipa-4.8.0.removed_csrgen/ipaclient/plugins/cert.py.orig	2019-07-03 13:24:38.478222573 +0200
e8574e
@@ -0,0 +1,215 @@
e8574e
+# Authors:
e8574e
+#   Andrew Wnuk <awnuk@redhat.com>
e8574e
+#   Jason Gerard DeRose <jderose@redhat.com>
e8574e
+#   John Dennis <jdennis@redhat.com>
e8574e
+#
e8574e
+# Copyright (C) 2009  Red Hat
e8574e
+# see file 'COPYING' for use and warranty information
e8574e
+#
e8574e
+# This program is free software; you can redistribute it and/or modify
e8574e
+# it under the terms of the GNU General Public License as published by
e8574e
+# the Free Software Foundation, either version 3 of the License, or
e8574e
+# (at your option) any later version.
e8574e
+#
e8574e
+# This program is distributed in the hope that it will be useful,
e8574e
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
e8574e
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
e8574e
+# GNU General Public License for more details.
e8574e
+#
e8574e
+# You should have received a copy of the GNU General Public License
e8574e
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
e8574e
+
e8574e
+import base64
e8574e
+
e8574e
+import six
e8574e
+
e8574e
+from ipaclient.frontend import MethodOverride
e8574e
+from ipalib import errors
e8574e
+from ipalib import x509
e8574e
+from ipalib import util
e8574e
+from ipalib.parameters import BinaryFile, File, Flag, Str
e8574e
+from ipalib.plugable import Registry
e8574e
+from ipalib.text import _
e8574e
+
e8574e
+if six.PY3:
e8574e
+    unicode = str
e8574e
+
e8574e
+register = Registry()
e8574e
+
e8574e
+
e8574e
+class CertRetrieveOverride(MethodOverride):
e8574e
+    takes_options = (
e8574e
+        Str(
e8574e
+            'certificate_out?',
e8574e
+            doc=_('Write certificate (chain if --chain used) to file'),
e8574e
+            include='cli',
e8574e
+            cli_metavar='FILE',
e8574e
+        ),
e8574e
+    )
e8574e
+
e8574e
+    def forward(self, *args, **options):
e8574e
+        if 'certificate_out' in options:
e8574e
+            certificate_out = options.pop('certificate_out')
e8574e
+            try:
e8574e
+                util.check_writable_file(certificate_out)
e8574e
+            except errors.FileError as e:
e8574e
+                raise errors.ValidationError(name='certificate-out',
e8574e
+                                             error=str(e))
e8574e
+        else:
e8574e
+            certificate_out = None
e8574e
+
e8574e
+        result = super(CertRetrieveOverride, self).forward(*args, **options)
e8574e
+
e8574e
+        if certificate_out is not None:
e8574e
+            if options.get('chain', False):
e8574e
+                certs = result['result']['certificate_chain']
e8574e
+            else:
e8574e
+                certs = [base64.b64decode(result['result']['certificate'])]
e8574e
+            certs = (x509.load_der_x509_certificate(cert) for cert in certs)
e8574e
+            x509.write_certificate_list(certs, certificate_out)
e8574e
+
e8574e
+        return result
e8574e
+
e8574e
+
e8574e
+@register(override=True, no_fail=True)
e8574e
+class cert_request(CertRetrieveOverride):
e8574e
+    takes_options = CertRetrieveOverride.takes_options + (
e8574e
+        Str(
e8574e
+            'database?',
e8574e
+            label=_('Path to NSS database'),
e8574e
+            doc=_('Path to NSS database to use for private key'),
e8574e
+        ),
e8574e
+        Str(
e8574e
+            'private_key?',
e8574e
+            label=_('Path to private key file'),
e8574e
+            doc=_('Path to PEM file containing a private key'),
e8574e
+        ),
e8574e
+        Str(
e8574e
+            'password_file?',
e8574e
+            label=_(
e8574e
+                'File containing a password for the private key or database'),
e8574e
+        ),
e8574e
+        Str(
e8574e
+            'csr_profile_id?',
e8574e
+            label=_('Name of CSR generation profile (if not the same as'
e8574e
+                    ' profile_id)'),
e8574e
+        ),
e8574e
+    )
e8574e
+
e8574e
+    def get_args(self):
e8574e
+        for arg in super(cert_request, self).get_args():
e8574e
+            if arg.name == 'csr':
e8574e
+                arg = arg.clone_retype(arg.name, File, required=False)
e8574e
+            yield arg
e8574e
+
e8574e
+    def forward(self, csr=None, **options):
e8574e
+        database = options.pop('database', None)
e8574e
+        private_key = options.pop('private_key', None)
e8574e
+        csr_profile_id = options.pop('csr_profile_id', None)
e8574e
+        password_file = options.pop('password_file', None)
e8574e
+
e8574e
+        if csr is None:
e8574e
+            # Deferred import, ipaclient.csrgen is expensive to load.
e8574e
+            # see https://pagure.io/freeipa/issue/7484
e8574e
+            from ipaclient import csrgen
e8574e
+
e8574e
+            if database:
e8574e
+                adaptor = csrgen.NSSAdaptor(database, password_file)
e8574e
+            elif private_key:
e8574e
+                adaptor = csrgen.OpenSSLAdaptor(
e8574e
+                    key_filename=private_key, password_filename=password_file)
e8574e
+            else:
e8574e
+                raise errors.InvocationError(
e8574e
+                    message=u"One of 'database' or 'private_key' is required")
e8574e
+
e8574e
+            pubkey_info = adaptor.get_subject_public_key_info()
e8574e
+            pubkey_info_b64 = base64.b64encode(pubkey_info)
e8574e
+
e8574e
+            # If csr_profile_id is passed, that takes precedence.
e8574e
+            # Otherwise, use profile_id. If neither are passed, the default
e8574e
+            # in cert_get_requestdata will be used.
e8574e
+            profile_id = csr_profile_id
e8574e
+            if profile_id is None:
e8574e
+                profile_id = options.get('profile_id')
e8574e
+
e8574e
+            response = self.api.Command.cert_get_requestdata(
e8574e
+                profile_id=profile_id,
e8574e
+                principal=options.get('principal'),
e8574e
+                public_key_info=pubkey_info_b64)
e8574e
+
e8574e
+            req_info_b64 = response['result']['request_info']
e8574e
+            req_info = base64.b64decode(req_info_b64)
e8574e
+
e8574e
+            csr = adaptor.sign_csr(req_info)
e8574e
+
e8574e
+            if not csr:
e8574e
+                raise errors.CertificateOperationError(
e8574e
+                    error=(_('Generated CSR was empty')))
e8574e
+
e8574e
+        else:
e8574e
+            if database is not None or private_key is not None:
e8574e
+                raise errors.MutuallyExclusiveError(reason=_(
e8574e
+                    "Options 'database' and 'private_key' are not compatible"
e8574e
+                    " with 'csr'"))
e8574e
+
e8574e
+        return super(cert_request, self).forward(csr, **options)
e8574e
+
e8574e
+
e8574e
+@register(override=True, no_fail=True)
e8574e
+class cert_show(CertRetrieveOverride):
e8574e
+    def get_options(self):
e8574e
+        for option in super(cert_show, self).get_options():
e8574e
+            if option.name == 'out':
e8574e
+                # skip server-defined --out
e8574e
+                continue
e8574e
+            if option.name == 'certificate_out':
e8574e
+                # add --out as a deprecated alias of --certificate-out
e8574e
+                option = option.clone_rename(
e8574e
+                    'out',
e8574e
+                    cli_name='certificate_out',
e8574e
+                    deprecated_cli_aliases={'out'},
e8574e
+                )
e8574e
+            yield option
e8574e
+
e8574e
+    def forward(self, *args, **options):
e8574e
+        try:
e8574e
+            options['certificate_out'] = options.pop('out')
e8574e
+        except KeyError:
e8574e
+            pass
e8574e
+
e8574e
+        return super(cert_show, self).forward(*args, **options)
e8574e
+
e8574e
+
e8574e
+@register(override=True, no_fail=True)
e8574e
+class cert_remove_hold(MethodOverride):
e8574e
+    has_output_params = (
e8574e
+        Flag('unrevoked',
e8574e
+            label=_('Unrevoked'),
e8574e
+        ),
e8574e
+        Str('error_string',
e8574e
+            label=_('Error'),
e8574e
+        ),
e8574e
+    )
e8574e
+
e8574e
+
e8574e
+@register(override=True, no_fail=True)
e8574e
+class cert_find(MethodOverride):
e8574e
+    takes_options = (
e8574e
+        BinaryFile(
e8574e
+            'file?',
e8574e
+            label=_("Input filename"),
e8574e
+            doc=_('File to load the certificate from.'),
e8574e
+            include='cli',
e8574e
+        ),
e8574e
+    )
e8574e
+
e8574e
+    def forward(self, *args, **options):
e8574e
+        if self.api.env.context == 'cli':
e8574e
+            if 'certificate' in options and 'file' in options:
e8574e
+                raise errors.MutuallyExclusiveError(
e8574e
+                    reason=_("cannot specify both raw certificate and file"))
e8574e
+            if 'certificate' not in options and 'file' in options:
e8574e
+                options['certificate'] = x509.load_unknown_x509_certificate(
e8574e
+                                            options.pop('file'))
e8574e
+
e8574e
+        return super(cert_find, self).forward(*args, **options)
e8574e
diff -urN freeipa-4.8.0/ipaclient/plugins/csrgen.py freeipa-4.8.0.removed_csrgen/ipaclient/plugins/csrgen.py
e8574e
--- freeipa-4.8.0/ipaclient/plugins/csrgen.py	2019-07-03 08:42:41.990537623 +0200
e8574e
+++ freeipa-4.8.0.removed_csrgen/ipaclient/plugins/csrgen.py	1970-01-01 01:00:00.000000000 +0100
b01884
@@ -1,128 +0,0 @@
b01884
-#
b01884
-# Copyright (C) 2016  FreeIPA Contributors see COPYING for license
b01884
-#
b01884
-
b01884
-import base64
b01884
-
b01884
-import six
b01884
-
b01884
-from ipalib import api
b01884
-from ipalib import errors
b01884
-from ipalib import output
b01884
-from ipalib import util
b01884
-from ipalib.frontend import Local, Str
b01884
-from ipalib.parameters import Bytes, Principal
b01884
-from ipalib.plugable import Registry
b01884
-from ipalib.text import _
b01884
-from ipapython import dogtag
b01884
-
b01884
-
b01884
-if six.PY3:
b01884
-    unicode = str
b01884
-
b01884
-register = Registry()
b01884
-
b01884
-__doc__ = _("""
b01884
-Commands to build certificate requests automatically
b01884
-""")
b01884
-
b01884
-
b01884
-@register()
b01884
-class cert_get_requestdata(Local):
b01884
-    __doc__ = _('Gather data for a certificate signing request.')
b01884
-
b01884
-    NO_CLI = True
b01884
-
b01884
-    takes_options = (
b01884
-        Principal(
b01884
-            'principal',
b01884
-            label=_('Principal'),
b01884
-            doc=_('Principal for this certificate (e.g.'
b01884
-                  ' HTTP/test.example.com)'),
b01884
-        ),
b01884
-        Str(
b01884
-            'profile_id?',
b01884
-            label=_('Profile ID'),
b01884
-            doc=_('CSR Generation Profile to use'),
b01884
-        ),
b01884
-        Bytes(
b01884
-            'public_key_info',
b01884
-            label=_('Subject Public Key Info'),
b01884
-            doc=_('DER-encoded SubjectPublicKeyInfo structure'),
b01884
-        ),
b01884
-        Str(
b01884
-            'out?',
b01884
-            doc=_('Write CertificationRequestInfo to file'),
b01884
-        ),
b01884
-    )
b01884
-
b01884
-    has_output = (
b01884
-        output.Output(
b01884
-            'result',
b01884
-            type=dict,
b01884
-            doc=_('Dictionary mapping variable name to value'),
b01884
-        ),
b01884
-    )
b01884
-
b01884
-    has_output_params = (
b01884
-        Str(
b01884
-            'request_info',
b01884
-            label=_('CertificationRequestInfo structure'),
b01884
-        )
b01884
-    )
b01884
-
b01884
-    def execute(self, *args, **options):
b01884
-        # Deferred import, ipaclient.csrgen is expensive to load.
b01884
-        # see https://pagure.io/freeipa/issue/7484
b01884
-        from ipaclient import csrgen
b01884
-        from ipaclient import csrgen_ffi
b01884
-
b01884
-        if 'out' in options:
b01884
-            util.check_writable_file(options['out'])
b01884
-
b01884
-        principal = options.get('principal')
b01884
-        profile_id = options.get('profile_id')
b01884
-        if profile_id is None:
b01884
-            profile_id = dogtag.DEFAULT_PROFILE
b01884
-        public_key_info = options.get('public_key_info')
b01884
-        public_key_info = base64.b64decode(public_key_info)
b01884
-
b01884
-        if self.api.env.in_server:
b01884
-            backend = self.api.Backend.ldap2
b01884
-        else:
b01884
-            backend = self.api.Backend.rpcclient
b01884
-        if not backend.isconnected():
b01884
-            backend.connect()
b01884
-
b01884
-        try:
b01884
-            if principal.is_host:
b01884
-                principal_obj = api.Command.host_show(
b01884
-                    principal.hostname, all=True)
b01884
-            elif principal.is_service:
b01884
-                principal_obj = api.Command.service_show(
b01884
-                    unicode(principal), all=True)
b01884
-            elif principal.is_user:
b01884
-                principal_obj = api.Command.user_show(
b01884
-                    principal.username, all=True)
b01884
-        except errors.NotFound:
b01884
-            raise errors.NotFound(
b01884
-                reason=_("The principal for this request doesn't exist."))
b01884
-        principal_obj = principal_obj['result']
b01884
-        config = api.Command.config_show()['result']
b01884
-
b01884
-        generator = csrgen.CSRGenerator(csrgen.FileRuleProvider())
b01884
-
b01884
-        csr_config = generator.csr_config(principal_obj, config, profile_id)
b01884
-        request_info = base64.b64encode(csrgen_ffi.build_requestinfo(
b01884
-            csr_config.encode('utf8'), public_key_info))
b01884
-
b01884
-        result = {}
b01884
-        if 'out' in options:
b01884
-            with open(options['out'], 'wb') as f:
b01884
-                f.write(request_info)
b01884
-        else:
b01884
-            result = dict(request_info=request_info)
b01884
-
b01884
-        return dict(
b01884
-            result=result
b01884
-        )
e8574e
diff -urN freeipa-4.8.0/ipaclient/setup.py freeipa-4.8.0.removed_csrgen/ipaclient/setup.py
e8574e
--- freeipa-4.8.0/ipaclient/setup.py	2019-07-03 08:42:41.836539916 +0200
e8574e
+++ freeipa-4.8.0.removed_csrgen/ipaclient/setup.py	2019-07-03 13:24:38.479222551 +0200
e8574e
@@ -41,13 +41,6 @@
b01884
             "ipaclient.remote_plugins.2_156",
b01884
             "ipaclient.remote_plugins.2_164",
b01884
         ],
b01884
-        package_data={
b01884
-            'ipaclient': [
b01884
-                'csrgen/profiles/*.json',
b01884
-                'csrgen/rules/*.json',
b01884
-                'csrgen/templates/*.tmpl',
b01884
-            ],
b01884
-        },
b01884
         install_requires=[
b01884
             "cryptography",
b01884
             "ipalib",
e8574e
@@ -63,7 +56,6 @@
b01884
         extras_require={
b01884
             "install": ["ipaplatform"],
b01884
             "otptoken_yubikey": ["python-yubico", "pyusb"],
b01884
-            "csrgen": ["cffi", "jinja2"],
e8574e
             "ldap": ["python-ldap"],  # ipapython.ipaldap
b01884
         },
b01884
         zip_safe=False,
e8574e
diff -urN freeipa-4.8.0/ipatests/test_ipaclient/data/test_csrgen/configs/caIPAserviceCert.conf freeipa-4.8.0.removed_csrgen/ipatests/test_ipaclient/data/test_csrgen/configs/caIPAserviceCert.conf
e8574e
--- freeipa-4.8.0/ipatests/test_ipaclient/data/test_csrgen/configs/caIPAserviceCert.conf	2019-07-03 08:42:45.972478335 +0200
e8574e
+++ freeipa-4.8.0.removed_csrgen/ipatests/test_ipaclient/data/test_csrgen/configs/caIPAserviceCert.conf	1970-01-01 01:00:00.000000000 +0100
b01884
@@ -1,16 +0,0 @@
b01884
-[ req ]
b01884
-prompt = no
b01884
-encrypt_key = no
b01884
-
b01884
-distinguished_name = sec0
b01884
-req_extensions = sec2
b01884
-
b01884
-[ sec0 ]
b01884
-O=DOMAIN.EXAMPLE.COM
b01884
-CN=machine.example.com
b01884
-
b01884
-[ sec1 ]
b01884
-DNS = machine.example.com
b01884
-
b01884
-[ sec2 ]
b01884
-subjectAltName = @sec1
e8574e
diff -urN freeipa-4.8.0/ipatests/test_ipaclient/data/test_csrgen/configs/userCert.conf freeipa-4.8.0.removed_csrgen/ipatests/test_ipaclient/data/test_csrgen/configs/userCert.conf
e8574e
--- freeipa-4.8.0/ipatests/test_ipaclient/data/test_csrgen/configs/userCert.conf	2019-07-03 08:42:45.976478276 +0200
e8574e
+++ freeipa-4.8.0.removed_csrgen/ipatests/test_ipaclient/data/test_csrgen/configs/userCert.conf	1970-01-01 01:00:00.000000000 +0100
b01884
@@ -1,16 +0,0 @@
b01884
-[ req ]
b01884
-prompt = no
b01884
-encrypt_key = no
b01884
-
b01884
-distinguished_name = sec0
b01884
-req_extensions = sec2
b01884
-
b01884
-[ sec0 ]
b01884
-O=DOMAIN.EXAMPLE.COM
b01884
-CN=testuser
b01884
-
b01884
-[ sec1 ]
b01884
-email = testuser@example.com
b01884
-
b01884
-[ sec2 ]
b01884
-subjectAltName = @sec1
e8574e
diff -urN freeipa-4.8.0/ipatests/test_ipaclient/data/test_csrgen/profiles/profile.json freeipa-4.8.0.removed_csrgen/ipatests/test_ipaclient/data/test_csrgen/profiles/profile.json
e8574e
--- freeipa-4.8.0/ipatests/test_ipaclient/data/test_csrgen/profiles/profile.json	2019-07-03 08:42:45.980478216 +0200
e8574e
+++ freeipa-4.8.0.removed_csrgen/ipatests/test_ipaclient/data/test_csrgen/profiles/profile.json	1970-01-01 01:00:00.000000000 +0100
b01884
@@ -1,8 +0,0 @@
b01884
-[
b01884
-    {
b01884
-        "syntax": "basic",
b01884
-        "data": [
b01884
-            "options"
b01884
-        ]
b01884
-    }
b01884
-]
e8574e
diff -urN freeipa-4.8.0/ipatests/test_ipaclient/data/test_csrgen/rules/basic.json freeipa-4.8.0.removed_csrgen/ipatests/test_ipaclient/data/test_csrgen/rules/basic.json
e8574e
--- freeipa-4.8.0/ipatests/test_ipaclient/data/test_csrgen/rules/basic.json	2019-07-03 08:42:45.984478157 +0200
e8574e
+++ freeipa-4.8.0.removed_csrgen/ipatests/test_ipaclient/data/test_csrgen/rules/basic.json	1970-01-01 01:00:00.000000000 +0100
b01884
@@ -1,5 +0,0 @@
b01884
-{
b01884
-  "rule": {
b01884
-    "template": "openssl_rule"
b01884
-  }
b01884
-}
e8574e
diff -urN freeipa-4.8.0/ipatests/test_ipaclient/data/test_csrgen/rules/options.json freeipa-4.8.0.removed_csrgen/ipatests/test_ipaclient/data/test_csrgen/rules/options.json
e8574e
--- freeipa-4.8.0/ipatests/test_ipaclient/data/test_csrgen/rules/options.json	2019-07-03 08:42:45.988478097 +0200
e8574e
+++ freeipa-4.8.0.removed_csrgen/ipatests/test_ipaclient/data/test_csrgen/rules/options.json	1970-01-01 01:00:00.000000000 +0100
b01884
@@ -1,8 +0,0 @@
b01884
-{
b01884
-  "rule": {
b01884
-    "template": "openssl_rule"
b01884
-  },
b01884
-  "options": {
b01884
-    "rule_option": true
b01884
-  }
b01884
-}
e8574e
diff -urN freeipa-4.8.0/ipatests/test_ipaclient/data/test_csrgen/templates/identity_base.tmpl freeipa-4.8.0.removed_csrgen/ipatests/test_ipaclient/data/test_csrgen/templates/identity_base.tmpl
e8574e
--- freeipa-4.8.0/ipatests/test_ipaclient/data/test_csrgen/templates/identity_base.tmpl	2019-07-03 08:42:45.993478023 +0200
e8574e
+++ freeipa-4.8.0.removed_csrgen/ipatests/test_ipaclient/data/test_csrgen/templates/identity_base.tmpl	1970-01-01 01:00:00.000000000 +0100
b01884
@@ -1 +0,0 @@
b01884
-{{ options|join(";") }}
e8574e
diff -urN freeipa-4.8.0/ipatests/test_ipaclient/test_csrgen.py freeipa-4.8.0.removed_csrgen/ipatests/test_ipaclient/test_csrgen.py
e8574e
--- freeipa-4.8.0/ipatests/test_ipaclient/test_csrgen.py	2019-07-03 08:42:45.963478469 +0200
e8574e
+++ freeipa-4.8.0.removed_csrgen/ipatests/test_ipaclient/test_csrgen.py	1970-01-01 01:00:00.000000000 +0100
b01884
@@ -1,304 +0,0 @@
b01884
-#
b01884
-# Copyright (C) 2016  FreeIPA Contributors see COPYING for license
b01884
-#
b01884
-
b01884
-import os
b01884
-import pytest
b01884
-
b01884
-from cryptography.hazmat.backends import default_backend
b01884
-from cryptography.hazmat.primitives.asymmetric import rsa
b01884
-from cryptography import x509
b01884
-
b01884
-from ipaclient import csrgen, csrgen_ffi
b01884
-from ipalib import errors
b01884
-
b01884
-BASE_DIR = os.path.dirname(__file__)
b01884
-CSR_DATA_DIR = os.path.join(BASE_DIR, 'data', 'test_csrgen')
b01884
-
b01884
-
b01884
-@pytest.fixture
b01884
-def formatter():
b01884
-    return csrgen.Formatter(csr_data_dir=CSR_DATA_DIR)
b01884
-
b01884
-
b01884
-@pytest.fixture
b01884
-def rule_provider():
b01884
-    return csrgen.FileRuleProvider(csr_data_dir=CSR_DATA_DIR)
b01884
-
b01884
-
b01884
-@pytest.fixture
b01884
-def generator():
b01884
-    return csrgen.CSRGenerator(csrgen.FileRuleProvider())
b01884
-
b01884
-
b01884
-class StubRuleProvider(csrgen.RuleProvider):
b01884
-    def __init__(self):
b01884
-        self.syntax_rule = csrgen.Rule(
b01884
-            'syntax', '{{datarules|join(",")}}', {})
b01884
-        self.data_rule = csrgen.Rule('data', 'data_template', {})
b01884
-        self.field_mapping = csrgen.FieldMapping(
b01884
-            'example', self.syntax_rule, [self.data_rule])
b01884
-        self.rules = [self.field_mapping]
b01884
-
b01884
-    def rules_for_profile(self, profile_id):
b01884
-        return self.rules
b01884
-
b01884
-
b01884
-class IdentityFormatter(csrgen.Formatter):
b01884
-    base_template_name = 'identity_base.tmpl'
b01884
-
b01884
-    def __init__(self):
b01884
-        super(IdentityFormatter, self).__init__(csr_data_dir=CSR_DATA_DIR)
b01884
-
b01884
-    def _get_template_params(self, syntax_rules):
b01884
-        return {'options': syntax_rules}
b01884
-
b01884
-
e8574e
-class test_Formatter:
b01884
-    def test_prepare_data_rule_with_data_source(self, formatter):
b01884
-        data_rule = csrgen.Rule('uid', '{{subject.uid.0}}',
b01884
-                                {'data_source': 'subject.uid.0'})
b01884
-        prepared = formatter._prepare_data_rule(data_rule)
b01884
-        assert prepared == '{% if subject.uid.0 %}{{subject.uid.0}}{% endif %}'
b01884
-
b01884
-    def test_prepare_data_rule_no_data_source(self, formatter):
b01884
-        """Not a normal case, but we should handle it anyway"""
b01884
-        data_rule = csrgen.Rule('uid', 'static_text', {})
b01884
-        prepared = formatter._prepare_data_rule(data_rule)
b01884
-        assert prepared == 'static_text'
b01884
-
b01884
-    def test_prepare_syntax_rule_with_data_sources(self, formatter):
b01884
-        syntax_rule = csrgen.Rule(
b01884
-            'example', '{{datarules|join(",")}}', {})
b01884
-        data_rules = ['{{subject.field1}}', '{{subject.field2}}']
b01884
-        data_sources = ['subject.field1', 'subject.field2']
b01884
-        prepared = formatter._prepare_syntax_rule(
b01884
-            syntax_rule, data_rules, 'example', data_sources)
b01884
-
b01884
-        assert prepared == (
b01884
-            '{% if subject.field1 or subject.field2 %}{{subject.field1}},'
b01884
-            '{{subject.field2}}{% endif %}')
b01884
-
b01884
-    def test_prepare_syntax_rule_with_combinator(self, formatter):
b01884
-        syntax_rule = csrgen.Rule('example', '{{datarules|join(",")}}',
b01884
-                                  {'data_source_combinator': 'and'})
b01884
-        data_rules = ['{{subject.field1}}', '{{subject.field2}}']
b01884
-        data_sources = ['subject.field1', 'subject.field2']
b01884
-        prepared = formatter._prepare_syntax_rule(
b01884
-            syntax_rule, data_rules, 'example', data_sources)
b01884
-
b01884
-        assert prepared == (
b01884
-            '{% if subject.field1 and subject.field2 %}{{subject.field1}},'
b01884
-            '{{subject.field2}}{% endif %}')
b01884
-
b01884
-    def test_prepare_syntax_rule_required(self, formatter):
b01884
-        syntax_rule = csrgen.Rule('example', '{{datarules|join(",")}}',
b01884
-                                  {'required': True})
b01884
-        data_rules = ['{{subject.field1}}']
b01884
-        data_sources = ['subject.field1']
b01884
-        prepared = formatter._prepare_syntax_rule(
b01884
-            syntax_rule, data_rules, 'example', data_sources)
b01884
-
b01884
-        assert prepared == (
b01884
-            '{% filter required("example") %}{% if subject.field1 %}'
b01884
-            '{{subject.field1}}{% endif %}{% endfilter %}')
b01884
-
b01884
-    def test_prepare_syntax_rule_passthrough(self, formatter):
b01884
-        """
b01884
-        Calls to macros defined as passthrough are still call tags in the final
b01884
-        template.
b01884
-        """
b01884
-        formatter._define_passthrough('example.macro')
b01884
-
b01884
-        syntax_rule = csrgen.Rule(
b01884
-            'example',
b01884
-            '{% call example.macro() %}{{datarules|join(",")}}{% endcall %}',
b01884
-            {})
b01884
-        data_rules = ['{{subject.field1}}']
b01884
-        data_sources = ['subject.field1']
b01884
-        prepared = formatter._prepare_syntax_rule(
b01884
-            syntax_rule, data_rules, 'example', data_sources)
b01884
-
b01884
-        assert prepared == (
b01884
-            '{% if subject.field1 %}{% call example.macro() %}'
b01884
-            '{{subject.field1}}{% endcall %}{% endif %}')
b01884
-
b01884
-    def test_prepare_syntax_rule_no_data_sources(self, formatter):
b01884
-        """Not a normal case, but we should handle it anyway"""
b01884
-        syntax_rule = csrgen.Rule(
b01884
-            'example', '{{datarules|join(",")}}', {})
b01884
-        data_rules = ['rule1', 'rule2']
b01884
-        data_sources = []
b01884
-        prepared = formatter._prepare_syntax_rule(
b01884
-            syntax_rule, data_rules, 'example', data_sources)
b01884
-
b01884
-        assert prepared == 'rule1,rule2'
b01884
-
b01884
-
e8574e
-class test_FileRuleProvider:
b01884
-    def test_rule_basic(self, rule_provider):
b01884
-        rule_name = 'basic'
b01884
-
b01884
-        rule = rule_provider._rule(rule_name)
b01884
-
b01884
-        assert rule.template == 'openssl_rule'
b01884
-
b01884
-    def test_rule_global_options(self, rule_provider):
b01884
-        rule_name = 'options'
b01884
-
b01884
-        rule = rule_provider._rule(rule_name)
b01884
-
b01884
-        assert rule.options['rule_option'] is True
b01884
-
b01884
-    def test_rule_nosuchrule(self, rule_provider):
b01884
-        with pytest.raises(errors.NotFound):
b01884
-            rule_provider._rule('nosuchrule')
b01884
-
b01884
-    def test_rules_for_profile_success(self, rule_provider):
b01884
-        rules = rule_provider.rules_for_profile('profile')
b01884
-
b01884
-        assert len(rules) == 1
b01884
-        field_mapping = rules[0]
b01884
-        assert field_mapping.syntax_rule.name == 'basic'
b01884
-        assert len(field_mapping.data_rules) == 1
b01884
-        assert field_mapping.data_rules[0].name == 'options'
b01884
-
b01884
-    def test_rules_for_profile_nosuchprofile(self, rule_provider):
b01884
-        with pytest.raises(errors.NotFound):
b01884
-            rule_provider.rules_for_profile('nosuchprofile')
b01884
-
b01884
-
e8574e
-class test_CSRGenerator:
b01884
-    def test_userCert_OpenSSL(self, generator):
b01884
-        principal = {
b01884
-            'uid': ['testuser'],
b01884
-            'mail': ['testuser@example.com'],
b01884
-        }
b01884
-        config = {
b01884
-            'ipacertificatesubjectbase': [
b01884
-                'O=DOMAIN.EXAMPLE.COM'
b01884
-            ],
b01884
-        }
b01884
-
b01884
-        script = generator.csr_config(principal, config, 'userCert')
b01884
-        with open(os.path.join(
b01884
-                CSR_DATA_DIR, 'configs', 'userCert.conf')) as f:
b01884
-            expected_script = f.read()
b01884
-        assert script == expected_script
b01884
-
b01884
-    def test_caIPAserviceCert_OpenSSL(self, generator):
b01884
-        principal = {
b01884
-            'krbprincipalname': [
b01884
-                'HTTP/machine.example.com@DOMAIN.EXAMPLE.COM'
b01884
-            ],
b01884
-        }
b01884
-        config = {
b01884
-            'ipacertificatesubjectbase': [
b01884
-                'O=DOMAIN.EXAMPLE.COM'
b01884
-            ],
b01884
-        }
b01884
-
b01884
-        script = generator.csr_config(
b01884
-            principal, config, 'caIPAserviceCert')
b01884
-        with open(os.path.join(
b01884
-                CSR_DATA_DIR, 'configs', 'caIPAserviceCert.conf')) as f:
b01884
-            expected_script = f.read()
b01884
-        assert script == expected_script
b01884
-
b01884
-    def test_works_with_lowercase_attr_type_shortname(self, generator):
b01884
-        principal = {
b01884
-            'uid': ['testuser'],
b01884
-            'mail': ['testuser@example.com'],
b01884
-        }
b01884
-        template_env = {
b01884
-            'ipacertificatesubjectbase': [
b01884
-                'o=DOMAIN.EXAMPLE.COM'  # lower-case attr type shortname
b01884
-            ],
b01884
-        }
b01884
-        config = generator.csr_config(principal, template_env, 'userCert')
b01884
-
b01884
-        key = rsa.generate_private_key(
b01884
-            public_exponent=65537,
b01884
-            key_size=2048,
b01884
-            backend=default_backend(),
b01884
-        )
b01884
-        adaptor = csrgen.OpenSSLAdaptor(key=key)
b01884
-
b01884
-        reqinfo = bytes(csrgen_ffi.build_requestinfo(
b01884
-            config.encode('utf-8'), adaptor.get_subject_public_key_info()))
b01884
-        csr_der = adaptor.sign_csr(reqinfo)
b01884
-        csr = x509.load_der_x509_csr(csr_der, default_backend())
b01884
-        assert (
b01884
-            csr.subject.get_attributes_for_oid(x509.NameOID.COMMON_NAME)
b01884
-            == [x509.NameAttribute(x509.NameOID.COMMON_NAME, u'testuser')]
b01884
-        )
b01884
-        assert (
b01884
-            csr.subject.get_attributes_for_oid(x509.NameOID.ORGANIZATION_NAME)
b01884
-            == [x509.NameAttribute(
b01884
-                x509.NameOID.ORGANIZATION_NAME, u'DOMAIN.EXAMPLE.COM')]
b01884
-        )
b01884
-
b01884
-    def test_unrecognised_attr_type_raises(self, generator):
b01884
-        principal = {
b01884
-            'uid': ['testuser'],
b01884
-            'mail': ['testuser@example.com'],
b01884
-        }
b01884
-        template_env = {
b01884
-            'ipacertificatesubjectbase': [
b01884
-                'X=DOMAIN.EXAMPLE.COM'  # unrecognised attr type
b01884
-            ],
b01884
-        }
b01884
-        config = generator.csr_config(principal, template_env, 'userCert')
b01884
-
b01884
-        key = rsa.generate_private_key(
b01884
-            public_exponent=65537,
b01884
-            key_size=2048,
b01884
-            backend=default_backend(),
b01884
-        )
b01884
-        adaptor = csrgen.OpenSSLAdaptor(key=key)
b01884
-
b01884
-        with pytest.raises(
b01884
-                errors.CSRTemplateError,
e8574e
-                match=r'^unrecognised attribute type: X$'):
b01884
-            csrgen_ffi.build_requestinfo(
b01884
-                config.encode('utf-8'), adaptor.get_subject_public_key_info())
b01884
-
b01884
-
e8574e
-class test_rule_handling:
b01884
-    def test_optionalAttributeMissing(self, generator):
b01884
-        principal = {'uid': 'testuser'}
b01884
-        rule_provider = StubRuleProvider()
b01884
-        rule_provider.data_rule.template = '{{subject.mail}}'
b01884
-        rule_provider.data_rule.options = {'data_source': 'subject.mail'}
b01884
-        generator = csrgen.CSRGenerator(
b01884
-            rule_provider, formatter_class=IdentityFormatter)
b01884
-
b01884
-        script = generator.csr_config(
b01884
-            principal, {}, 'example')
b01884
-        assert script == '\n'
b01884
-
b01884
-    def test_twoDataRulesOneMissing(self, generator):
b01884
-        principal = {'uid': 'testuser'}
b01884
-        rule_provider = StubRuleProvider()
b01884
-        rule_provider.data_rule.template = '{{subject.mail}}'
b01884
-        rule_provider.data_rule.options = {'data_source': 'subject.mail'}
b01884
-        rule_provider.field_mapping.data_rules.append(csrgen.Rule(
b01884
-            'data2', '{{subject.uid}}', {'data_source': 'subject.uid'}))
b01884
-        generator = csrgen.CSRGenerator(
b01884
-            rule_provider, formatter_class=IdentityFormatter)
b01884
-
b01884
-        script = generator.csr_config(principal, {}, 'example')
b01884
-        assert script == ',testuser\n'
b01884
-
b01884
-    def test_requiredAttributeMissing(self):
b01884
-        principal = {'uid': 'testuser'}
b01884
-        rule_provider = StubRuleProvider()
b01884
-        rule_provider.data_rule.template = '{{subject.mail}}'
b01884
-        rule_provider.data_rule.options = {'data_source': 'subject.mail'}
b01884
-        rule_provider.syntax_rule.options = {'required': True}
b01884
-        generator = csrgen.CSRGenerator(
b01884
-            rule_provider, formatter_class=IdentityFormatter)
b01884
-
b01884
-        with pytest.raises(errors.CSRTemplateError):
b01884
-            _script = generator.csr_config(
b01884
-                principal, {}, 'example')