pgreco / rpms / ipa

Forked from forks/areguera/rpms/ipa 4 years ago
Clone

Blame SOURCES/1002-4.7.90pre1-Remove-csrgen.patch

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