387014f928
required for building freeipa-4.5.x in rawhide
5788 lines
214 KiB
Diff
5788 lines
214 KiB
Diff
From db36dca3d45e6eefbb30042ee65876566f1a6014 Mon Sep 17 00:00:00 2001
|
||
From: Sumit Bose <sbose@redhat.com>
|
||
Date: Thu, 2 Feb 2017 11:24:02 +0100
|
||
Subject: [PATCH 06/97] certmap: add new library libsss_certmap
|
||
MIME-Version: 1.0
|
||
Content-Type: text/plain; charset=UTF-8
|
||
Content-Transfer-Encoding: 8bit
|
||
|
||
With this library it would be possible to map certificates and users not
|
||
only by adding the full certificate to the user's LDAP object but by
|
||
adding e.g. only parts like the issuer and subject name. Additionally
|
||
the library is also able to flexible select/match certificates based on
|
||
values in the certificate.
|
||
|
||
Details about mapping and matching rules can be found in the included
|
||
man page.
|
||
|
||
Related to https://pagure.io/SSSD/sssd/issue/3050
|
||
|
||
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
|
||
Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
|
||
---
|
||
Makefile.am | 55 ++
|
||
configure.ac | 1 +
|
||
contrib/sssd.spec.in | 32 +
|
||
src/lib/certmap/sss_cert_content_nss.c | 1014 +++++++++++++++++++
|
||
src/lib/certmap/sss_certmap.c | 993 +++++++++++++++++++
|
||
src/lib/certmap/sss_certmap.doxy.in | 3 +
|
||
src/lib/certmap/sss_certmap.exports | 13 +
|
||
src/lib/certmap/sss_certmap.h | 155 +++
|
||
src/lib/certmap/sss_certmap.pc.in | 11 +
|
||
src/lib/certmap/sss_certmap_attr_names.c | 107 +++
|
||
src/lib/certmap/sss_certmap_int.h | 187 ++++
|
||
src/lib/certmap/sss_certmap_krb5_match.c | 558 +++++++++++
|
||
src/lib/certmap/sss_certmap_ldap_mapping.c | 367 +++++++
|
||
src/man/Makefile.am | 2 +-
|
||
src/man/po/po4a.cfg | 1 +
|
||
src/man/sss-certmap.5.xml | 600 ++++++++++++
|
||
src/tests/cmocka/test_certmap.c | 1443 ++++++++++++++++++++++++++++
|
||
src/tests/dlopen-tests.c | 1 +
|
||
18 files changed, 5542 insertions(+), 1 deletion(-)
|
||
create mode 100644 src/lib/certmap/sss_cert_content_nss.c
|
||
create mode 100644 src/lib/certmap/sss_certmap.c
|
||
create mode 100644 src/lib/certmap/sss_certmap.doxy.in
|
||
create mode 100644 src/lib/certmap/sss_certmap.exports
|
||
create mode 100644 src/lib/certmap/sss_certmap.h
|
||
create mode 100644 src/lib/certmap/sss_certmap.pc.in
|
||
create mode 100644 src/lib/certmap/sss_certmap_attr_names.c
|
||
create mode 100644 src/lib/certmap/sss_certmap_int.h
|
||
create mode 100644 src/lib/certmap/sss_certmap_krb5_match.c
|
||
create mode 100644 src/lib/certmap/sss_certmap_ldap_mapping.c
|
||
create mode 100644 src/man/sss-certmap.5.xml
|
||
create mode 100644 src/tests/cmocka/test_certmap.c
|
||
|
||
diff --git a/Makefile.am b/Makefile.am
|
||
index 6dae4f2dd7f2dee501add82c7ab4f15fcbcc59ac..8ca12c10d2713b6a72361d84b25486500c79f407 100644
|
||
--- a/Makefile.am
|
||
+++ b/Makefile.am
|
||
@@ -278,6 +278,7 @@ if HAVE_CMOCKA
|
||
simple-access-tests \
|
||
krb5_common_test \
|
||
test_iobuf \
|
||
+ sss_certmap_test \
|
||
$(NULL)
|
||
|
||
if HAVE_LIBRESOLV
|
||
@@ -1074,6 +1075,7 @@ SSSD_INTERNAL_LTLIBS = \
|
||
lib_LTLIBRARIES = libipa_hbac.la \
|
||
libsss_idmap.la \
|
||
libsss_nss_idmap.la \
|
||
+ libsss_certmap.la \
|
||
$(NULL)
|
||
|
||
pkgconfig_DATA += src/lib/ipa_hbac/ipa_hbac.pc
|
||
@@ -1128,6 +1130,7 @@ include_HEADERS = \
|
||
src/lib/ipa_hbac/ipa_hbac.h \
|
||
src/lib/idmap/sss_idmap.h \
|
||
src/sss_client/idmap/sss_nss_idmap.h \
|
||
+ src/lib/certmap/sss_certmap.h \
|
||
$(NULL)
|
||
|
||
if BUILD_LIBWBCLIENT
|
||
@@ -1712,6 +1715,38 @@ sssd_check_socket_activated_responders_LDADD = \
|
||
$(NULL)
|
||
endif
|
||
|
||
+if HAVE_NSS
|
||
+pkgconfig_DATA += src/lib/certmap/sss_certmap.pc
|
||
+libsss_certmap_la_DEPENDENCIES = src/lib/certmap/sss_certmap.exports
|
||
+libsss_certmap_la_SOURCES = \
|
||
+ src/lib/certmap/sss_certmap.c \
|
||
+ src/lib/certmap/sss_certmap_attr_names.c \
|
||
+ src/lib/certmap/sss_cert_content_nss.c \
|
||
+ src/lib/certmap/sss_certmap_krb5_match.c \
|
||
+ src/lib/certmap/sss_certmap_ldap_mapping.c \
|
||
+ src/util/util_ext.c \
|
||
+ src/util/cert/cert_common.c \
|
||
+ src/util/crypto/nss/nss_base64.c \
|
||
+ src/util/cert/nss/cert.c \
|
||
+ src/util/crypto/nss/nss_util.c \
|
||
+ $(NULL)
|
||
+libsss_certmap_la_CFLAGS = \
|
||
+ $(AM_CFLAGS) \
|
||
+ $(TALLOC_CFLAGS) \
|
||
+ $(NSS_CFLAGS) \
|
||
+ $(NULL)
|
||
+libsss_certmap_la_LIBADD = \
|
||
+ $(TALLOC_LIBS) \
|
||
+ $(NSS_LIBS) \
|
||
+ $(NULL)
|
||
+libsss_certmap_la_LDFLAGS = \
|
||
+ -Wl,--version-script,$(srcdir)/src/lib/certmap/sss_certmap.exports \
|
||
+ -version-info 0:0:0
|
||
+
|
||
+dist_noinst_DATA += src/lib/certmap/sss_certmap.exports
|
||
+dist_noinst_HEADERS += src/lib/certmap/sss_certmap_int.h
|
||
+endif
|
||
+
|
||
#################
|
||
# Feature Tests #
|
||
#################
|
||
@@ -3245,6 +3280,25 @@ test_inotify_LDADD = \
|
||
libsss_test_common.la \
|
||
$(NULL)
|
||
|
||
+if HAVE_NSS
|
||
+sss_certmap_test_SOURCES = \
|
||
+ src/tests/cmocka/test_certmap.c \
|
||
+ src/lib/certmap/sss_certmap_attr_names.c \
|
||
+ $(NULL)
|
||
+sss_certmap_test_CFLAGS = \
|
||
+ $(AM_CFLAGS) \
|
||
+ $(NSS_CFLAGS) \
|
||
+ $(NULL)
|
||
+sss_certmap_test_LDADD = \
|
||
+ $(CMOCKA_LIBS) \
|
||
+ $(POPT_LIBS) \
|
||
+ $(TALLOC_LIBS) \
|
||
+ $(NSS_LIBS) \
|
||
+ $(SSSD_INTERNAL_LTLIBS) \
|
||
+ libsss_test_common.la \
|
||
+ libsss_certmap.la \
|
||
+ $(NULL)
|
||
+endif
|
||
endif # HAVE_CMOCKA
|
||
|
||
noinst_PROGRAMS = pam_test_client
|
||
@@ -4404,6 +4458,7 @@ docs:
|
||
$(DOXYGEN) src/lib/ipa_hbac/ipa_hbac.doxy
|
||
$(DOXYGEN) src/lib/idmap/sss_idmap.doxy
|
||
$(DOXYGEN) src/sss_client/idmap/sss_nss_idmap.doxy
|
||
+ $(DOXYGEN) src/lib/certmap/sss_certmap.doxy
|
||
if BUILD_IFP
|
||
$(DOXYGEN) src/lib/sifp/sss_simpleifp.doxy
|
||
endif
|
||
diff --git a/configure.ac b/configure.ac
|
||
index e6a3b4e857bcbec16873f54008e6b42aeb9b7cd7..dd1012015a5fea9f25e5b5199b4868fbc0bc14c4 100644
|
||
--- a/configure.ac
|
||
+++ b/configure.ac
|
||
@@ -483,6 +483,7 @@ AC_CONFIG_FILES([Makefile contrib/sssd.spec src/examples/rwtab src/doxy.config
|
||
src/tests/intg/Makefile
|
||
src/lib/ipa_hbac/ipa_hbac.pc src/lib/ipa_hbac/ipa_hbac.doxy
|
||
src/lib/idmap/sss_idmap.pc src/lib/idmap/sss_idmap.doxy
|
||
+ src/lib/certmap/sss_certmap.pc src/lib/certmap/sss_certmap.doxy
|
||
src/sss_client/idmap/sss_nss_idmap.pc
|
||
src/sss_client/idmap/sss_nss_idmap.doxy
|
||
src/sss_client/libwbclient/wbclient_sssd.pc
|
||
diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in
|
||
index 5bd2beb89014ba7c86b4231f0357a7a6e10a18a8..28ebe07a26a3112210b092b7831e7f6aae061c8d 100644
|
||
--- a/contrib/sssd.spec.in
|
||
+++ b/contrib/sssd.spec.in
|
||
@@ -658,6 +658,25 @@ The libnfsidmap sssd module provides a way for rpc.idmapd to call SSSD to map
|
||
UIDs/GIDs to names and vice versa. It can be also used for mapping principal
|
||
(user) name to IDs(UID or GID) or to obtain groups which user are member of.
|
||
|
||
+%package -n libsss_certmap
|
||
+Summary: SSSD Certficate Mapping Library
|
||
+Group: Development/Libraries
|
||
+License: LGPLv3+
|
||
+Requires(post): /sbin/ldconfig
|
||
+Requires(postun): /sbin/ldconfig
|
||
+
|
||
+%description -n libsss_certmap
|
||
+Library to map certificates to users based on rules
|
||
+
|
||
+%package -n libsss_certmap-devel
|
||
+Summary: SSSD Certficate Mapping Library
|
||
+Group: Development/Libraries
|
||
+License: LGPLv3+
|
||
+Requires: libsss_certmap = %{version}-%{release}
|
||
+
|
||
+%description -n libsss_certmap-devel
|
||
+Library to map certificates to users based on rules
|
||
+
|
||
%prep
|
||
%setup -q -n %{name}-%{version}
|
||
|
||
@@ -888,6 +907,7 @@ done
|
||
%{_datadir}/sssd/sssd.api.d
|
||
%{_mandir}/man1/sss_ssh_authorizedkeys.1*
|
||
%{_mandir}/man1/sss_ssh_knownhostsproxy.1*
|
||
+%{_mandir}/man5/sss-certmap.5*
|
||
%{_mandir}/man5/sssd.conf.5*
|
||
%{_mandir}/man5/sssd-simple.5*
|
||
%{_mandir}/man5/sssd-sudo.5*
|
||
@@ -1146,6 +1166,18 @@ done
|
||
%files nfs-idmap
|
||
%{_libdir}/libnfsidmap/sss.so
|
||
|
||
+%files -n libsss_certmap
|
||
+%defattr(-,root,root,-)
|
||
+%doc src/sss_client/COPYING src/sss_client/COPYING.LESSER
|
||
+%{_libdir}/libsss_certmap.so.*
|
||
+
|
||
+%files -n libsss_certmap-devel
|
||
+%defattr(-,root,root,-)
|
||
+%doc certmap_doc/html
|
||
+%{_includedir}/sss_certmap.h
|
||
+%{_libdir}/libsss_certmap.so
|
||
+%{_libdir}/pkgconfig/sss_certmap.pc
|
||
+
|
||
%pre common
|
||
getent group sssd >/dev/null || groupadd -r sssd
|
||
getent passwd sssd >/dev/null || useradd -r -g sssd -d / -s /sbin/nologin -c "User for sssd" sssd
|
||
diff --git a/src/lib/certmap/sss_cert_content_nss.c b/src/lib/certmap/sss_cert_content_nss.c
|
||
new file mode 100644
|
||
index 0000000000000000000000000000000000000000..d3182895465706c87503b8abb0cea49b7677625d
|
||
--- /dev/null
|
||
+++ b/src/lib/certmap/sss_cert_content_nss.c
|
||
@@ -0,0 +1,1014 @@
|
||
+/*
|
||
+ SSSD - certificate handling utils - NSS version
|
||
+ The calls defined here should be useable outside of SSSD as well, e.g. in
|
||
+ libsss_certmap.
|
||
+
|
||
+ Copyright (C) Sumit Bose <sbose@redhat.com> 2017
|
||
+
|
||
+ This program is free software; you can redistribute it and/or modify
|
||
+ it under the terms of the GNU General Public License as published by
|
||
+ the Free Software Foundation; either version 3 of the License, or
|
||
+ (at your option) any later version.
|
||
+
|
||
+ This program is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
+ GNU General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU General Public License
|
||
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
+*/
|
||
+
|
||
+#include "config.h"
|
||
+
|
||
+#include <nss.h>
|
||
+#include <cert.h>
|
||
+#include <base64.h>
|
||
+#include <prerror.h>
|
||
+#include <secport.h>
|
||
+#include <secerr.h>
|
||
+#include <prprf.h>
|
||
+#include <prnetdb.h>
|
||
+#include <talloc.h>
|
||
+
|
||
+#include "util/crypto/sss_crypto.h"
|
||
+#include "util/crypto/nss/nss_util.h"
|
||
+#include "util/cert.h"
|
||
+#include "lib/certmap/sss_certmap.h"
|
||
+#include "lib/certmap/sss_certmap_int.h"
|
||
+
|
||
+
|
||
+/* The following two functions are copied from NSS's lib/certdb/secname.c
|
||
+ * becasue CERT_AddAVA is not exported. I just renamed it and made it static
|
||
+ * to avoid issues if the call gets exported some time in future. */
|
||
+
|
||
+static void **
|
||
+AddToArray(PLArenaPool *arena, void **array, void *element)
|
||
+{
|
||
+ unsigned count;
|
||
+ void **ap;
|
||
+
|
||
+ /* Count up number of slots already in use in the array */
|
||
+ count = 0;
|
||
+ ap = array;
|
||
+ if (ap) {
|
||
+ while (*ap++) {
|
||
+ count++;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (array) {
|
||
+ array = (void**) PORT_ArenaGrow(arena, array,
|
||
+ (count + 1) * sizeof(void *),
|
||
+ (count + 2) * sizeof(void *));
|
||
+ } else {
|
||
+ array = (void**) PORT_ArenaAlloc(arena, (count + 2) * sizeof(void *));
|
||
+ }
|
||
+ if (array) {
|
||
+ array[count] = element;
|
||
+ array[count+1] = 0;
|
||
+ }
|
||
+ return array;
|
||
+}
|
||
+
|
||
+
|
||
+static SECStatus
|
||
+sss_CERT_AddAVA(PLArenaPool *arena, CERTRDN *rdn, CERTAVA *ava)
|
||
+{
|
||
+ rdn->avas = (CERTAVA**) AddToArray(arena, (void**) rdn->avas, ava);
|
||
+ return rdn->avas ? SECSuccess : SECFailure;
|
||
+}
|
||
+
|
||
+static SECItem *
|
||
+cert_get_ext_by_tag(CERTCertificate *cert, SECOidTag tag)
|
||
+{
|
||
+ SECOidData *oid;
|
||
+ int i;
|
||
+
|
||
+ oid = SECOID_FindOIDByTag(tag);
|
||
+ for (i = 0;
|
||
+ (cert->extensions != NULL) && (cert->extensions[i] != NULL);
|
||
+ i++)
|
||
+ if (SECITEM_ItemsAreEqual(&cert->extensions[i]->id, &oid->oid))
|
||
+ return &cert->extensions[i]->value;
|
||
+ return NULL;
|
||
+}
|
||
+
|
||
+static int get_extended_key_usage_oids(TALLOC_CTX *mem_ctx,
|
||
+ CERTCertificate *cert,
|
||
+ const char ***_oids)
|
||
+{
|
||
+ PLArenaPool *pool;
|
||
+ SECItem *ext;
|
||
+ SECItem **oids = NULL;
|
||
+ const char **oids_list = NULL;
|
||
+ size_t c;
|
||
+ SECStatus rv;
|
||
+ char *tmp_str;
|
||
+ int ret;
|
||
+
|
||
+ pool = PORT_NewArena(sizeof(double));
|
||
+ ext = cert_get_ext_by_tag(cert, SEC_OID_X509_EXT_KEY_USAGE);
|
||
+ if (ext != NULL) {
|
||
+ rv = SEC_ASN1DecodeItem(pool, &oids,
|
||
+ SEC_ASN1_GET(SEC_SequenceOfObjectIDTemplate),
|
||
+ ext);
|
||
+ if (rv != SECSuccess) {
|
||
+ ret = EINVAL;
|
||
+ goto done;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ for (c = 0; (oids != NULL && oids[c] != NULL); c++);
|
||
+ oids_list = talloc_zero_array(mem_ctx, const char *, c + 1);
|
||
+ if (oids_list == NULL) {
|
||
+ return ENOMEM;
|
||
+ }
|
||
+
|
||
+ for (c = 0; (oids != NULL && oids[c] != NULL); c++) {
|
||
+ tmp_str = CERT_GetOidString(oids[c]);
|
||
+ /* is it expexted that NSS OID strings start with "OID." but we
|
||
+ * prefer the plain dotted-decimal version so the prefix is skipped */
|
||
+ if (tmp_str == NULL || strncmp(tmp_str, "OID.", 4) != 0) {
|
||
+ PR_smprintf_free(tmp_str);
|
||
+ ret = EINVAL;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ oids_list[c] = talloc_strdup(oids_list, tmp_str + 4);
|
||
+ PR_smprintf_free(tmp_str);
|
||
+ if(oids_list[c] == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ ret = 0;
|
||
+
|
||
+done:
|
||
+ PORT_FreeArena(pool, PR_TRUE);
|
||
+ if (ret == 0) {
|
||
+ *_oids = oids_list;
|
||
+ } else {
|
||
+ talloc_free(oids_list);
|
||
+ }
|
||
+
|
||
+ return ret;
|
||
+
|
||
+}
|
||
+
|
||
+static int get_rdn_str(TALLOC_CTX *mem_ctx, CERTAVA **avas,
|
||
+ const char **rdn_str)
|
||
+{
|
||
+ size_t c;
|
||
+ char *tmp_name = NULL;
|
||
+ const char *tmp_str = NULL;
|
||
+ int ret;
|
||
+ SECStatus rv;
|
||
+ CERTRDN rdn = { 0 };
|
||
+ CERTName *name = NULL;
|
||
+ PLArenaPool *arena = NULL;
|
||
+
|
||
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
||
+ if (arena == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+
|
||
+ /* Multiple AVAs should be avoided becasue there is no general ordering
|
||
+ * rule and the RDN strings are not reproducible */
|
||
+ for (c = 0; avas[c] != NULL; c++) {
|
||
+ rv = sss_CERT_AddAVA(arena, &rdn, avas[c]);
|
||
+ if (rv != SECSuccess) {
|
||
+ ret = EIO;
|
||
+ goto done;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ name = CERT_CreateName(&rdn, NULL);
|
||
+ if (name == NULL) {
|
||
+ ret = EIO;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ tmp_name = CERT_NameToAscii(name);
|
||
+ CERT_DestroyName(name);
|
||
+ if (tmp_name == NULL) {
|
||
+ ret = EIO;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ tmp_str = talloc_strdup(mem_ctx, tmp_name);
|
||
+ PORT_Free(tmp_name);
|
||
+ if (tmp_str == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ ret = 0;
|
||
+
|
||
+done:
|
||
+ if (ret == 0) {
|
||
+ *rdn_str = tmp_str;
|
||
+ } else {
|
||
+ talloc_free(discard_const(tmp_str));
|
||
+ }
|
||
+ PORT_FreeArena(arena, PR_FALSE);
|
||
+
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+static int get_rdn_list(TALLOC_CTX *mem_ctx, CERTRDN **rdns,
|
||
+ const char ***rdn_list)
|
||
+{
|
||
+ int ret;
|
||
+ size_t c;
|
||
+ const char **list = NULL;
|
||
+
|
||
+ for (c = 0; rdns[c] != NULL; c++);
|
||
+ list = talloc_zero_array(mem_ctx, const char *, c + 1);
|
||
+ if (list == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+ for (c = 0; rdns[c] != NULL; c++) {
|
||
+ ret = get_rdn_str(list, rdns[c]->avas,
|
||
+ &(list[c]));
|
||
+ if (ret != 0) {
|
||
+ goto done;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ ret = 0;
|
||
+
|
||
+done:
|
||
+ if (ret == 0) {
|
||
+ *rdn_list = list;
|
||
+ } else {
|
||
+ talloc_free(list);
|
||
+ }
|
||
+
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+enum san_opt nss_name_type_to_san_opt(CERTGeneralNameType type)
|
||
+{
|
||
+ switch (type) {
|
||
+ case certOtherName:
|
||
+ return SAN_OTHER_NAME;
|
||
+ case certRFC822Name:
|
||
+ return SAN_RFC822_NAME;
|
||
+ case certDNSName:
|
||
+ return SAN_DNS_NAME;
|
||
+ case certX400Address:
|
||
+ return SAN_X400_ADDRESS;
|
||
+ case certDirectoryName:
|
||
+ return SAN_DIRECTORY_NAME;
|
||
+ case certEDIPartyName:
|
||
+ return SAN_EDIPART_NAME;
|
||
+ case certURI:
|
||
+ return SAN_URI;
|
||
+ case certIPAddress:
|
||
+ return SAN_IP_ADDRESS;
|
||
+ case certRegisterID:
|
||
+ return SAN_REGISTERED_ID;
|
||
+ default:
|
||
+ return SAN_INVALID;
|
||
+ }
|
||
+}
|
||
+
|
||
+static int add_to_san_list(TALLOC_CTX *mem_ctx, bool is_bin,
|
||
+ enum san_opt san_opt, uint8_t *data, size_t len,
|
||
+ struct san_list **item)
|
||
+{
|
||
+ struct san_list *i;
|
||
+
|
||
+ if (data == NULL || len == 0 || san_opt == SAN_INVALID) {
|
||
+ return EINVAL;
|
||
+ }
|
||
+
|
||
+ i = talloc_zero(mem_ctx, struct san_list);
|
||
+ if (i == NULL) {
|
||
+ return ENOMEM;
|
||
+ }
|
||
+
|
||
+ i->san_opt = san_opt;
|
||
+ if (is_bin) {
|
||
+ i->bin_val = talloc_memdup(i, data, len);
|
||
+ i->bin_val_len = len;
|
||
+ } else {
|
||
+ i->val = talloc_strndup(i, (char *) data, len);
|
||
+ }
|
||
+ if (i->val == NULL) {
|
||
+ talloc_free(i);
|
||
+ return ENOMEM;
|
||
+ }
|
||
+
|
||
+ *item = i;
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+/* taken from pkinit_crypto_nss.c of MIT Kerberos */
|
||
+/* KerberosString: RFC 4120, 5.2.1. */
|
||
+static const SEC_ASN1Template kerberos_string_template[] = {
|
||
+ {
|
||
+ SEC_ASN1_GENERAL_STRING,
|
||
+ 0,
|
||
+ NULL,
|
||
+ sizeof(SECItem),
|
||
+ }
|
||
+};
|
||
+
|
||
+/* Realm: RFC 4120, 5.2.2. */
|
||
+struct realm {
|
||
+ SECItem name;
|
||
+};
|
||
+static const SEC_ASN1Template realm_template[] = {
|
||
+ {
|
||
+ SEC_ASN1_GENERAL_STRING,
|
||
+ 0,
|
||
+ NULL,
|
||
+ sizeof(SECItem),
|
||
+ }
|
||
+};
|
||
+
|
||
+/* PrincipalName: RFC 4120, 5.2.2. */
|
||
+static const SEC_ASN1Template sequence_of_kerberos_string_template[] = {
|
||
+ {
|
||
+ SEC_ASN1_SEQUENCE_OF,
|
||
+ 0,
|
||
+ &kerberos_string_template,
|
||
+ 0,
|
||
+ }
|
||
+};
|
||
+
|
||
+struct principal_name {
|
||
+ SECItem name_type;
|
||
+ SECItem **name_string;
|
||
+};
|
||
+static const SEC_ASN1Template principal_name_template[] = {
|
||
+ {
|
||
+ SEC_ASN1_SEQUENCE,
|
||
+ 0,
|
||
+ NULL,
|
||
+ sizeof(struct principal_name),
|
||
+ },
|
||
+ {
|
||
+ SEC_ASN1_CONTEXT_SPECIFIC | 0 | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT,
|
||
+ offsetof(struct principal_name, name_type),
|
||
+ &SEC_IntegerTemplate,
|
||
+ sizeof(SECItem),
|
||
+ },
|
||
+ {
|
||
+ SEC_ASN1_CONTEXT_SPECIFIC | 1 | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT,
|
||
+ offsetof(struct principal_name, name_string),
|
||
+ sequence_of_kerberos_string_template,
|
||
+ sizeof(struct SECItem **),
|
||
+ },
|
||
+ {0, 0, NULL, 0},
|
||
+};
|
||
+
|
||
+/* KRB5PrincipalName: RFC 4556, 3.2.2. */
|
||
+struct kerberos_principal_name {
|
||
+ SECItem realm;
|
||
+ struct principal_name principal_name;
|
||
+};
|
||
+static const SEC_ASN1Template kerberos_principal_name_template[] = {
|
||
+ {
|
||
+ SEC_ASN1_SEQUENCE,
|
||
+ 0,
|
||
+ NULL,
|
||
+ sizeof(struct kerberos_principal_name),
|
||
+ },
|
||
+ {
|
||
+ SEC_ASN1_CONTEXT_SPECIFIC | 0 | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT,
|
||
+ offsetof(struct kerberos_principal_name, realm),
|
||
+ &realm_template,
|
||
+ sizeof(struct realm),
|
||
+ },
|
||
+ {
|
||
+ SEC_ASN1_CONTEXT_SPECIFIC | 1 | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT,
|
||
+ offsetof(struct kerberos_principal_name, principal_name),
|
||
+ &principal_name_template,
|
||
+ sizeof(struct principal_name),
|
||
+ },
|
||
+ {0, 0, NULL, 0}
|
||
+};
|
||
+
|
||
+#define PKINIT_OID "1.3.6.1.5.2.2"
|
||
+#define NT_PRINCIPAL_OID "1.3.6.1.4.1.311.20.2.3"
|
||
+
|
||
+static int add_string_other_name_to_san_list(TALLOC_CTX *mem_ctx,
|
||
+ enum san_opt san_opt,
|
||
+ CERTGeneralName *current,
|
||
+ struct san_list **item)
|
||
+{
|
||
+ struct san_list *i = NULL;
|
||
+ int ret;
|
||
+ char *tmp_str;
|
||
+
|
||
+ tmp_str = CERT_GetOidString(&(current->name.OthName.oid));
|
||
+ /* is it expexted that NSS OID strings start with "OID." but we
|
||
+ * prefer the plain dotted-decimal version so the prefix is skipped */
|
||
+ if (tmp_str == NULL || strncmp(tmp_str, "OID.", 4) != 0) {
|
||
+ PR_smprintf_free(tmp_str);
|
||
+ return EINVAL;
|
||
+ }
|
||
+
|
||
+ i = talloc_zero(mem_ctx, struct san_list);
|
||
+ if (i == NULL) {
|
||
+ PR_smprintf_free(tmp_str);
|
||
+ return ENOMEM;
|
||
+ }
|
||
+ i->san_opt = san_opt;
|
||
+
|
||
+ i->other_name_oid = talloc_strdup(i, tmp_str + 4);
|
||
+ PR_smprintf_free(tmp_str);
|
||
+ if (i->other_name_oid == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ i->bin_val = talloc_memdup(i, current->name.OthName.name.data,
|
||
+ current->name.OthName.name.len);
|
||
+ if (i->bin_val == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+ i->bin_val_len = current->name.OthName.name.len;
|
||
+
|
||
+ ret = 0;
|
||
+
|
||
+done:
|
||
+ if (ret == 0) {
|
||
+ *item = i;
|
||
+ } else {
|
||
+ talloc_free(i);
|
||
+ }
|
||
+
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+static int get_short_name(TALLOC_CTX *mem_ctx, const char *full_name,
|
||
+ char delim, char **short_name)
|
||
+{
|
||
+ char *at;
|
||
+ char *s;
|
||
+
|
||
+ if (full_name == NULL || delim == '\0' || short_name == NULL) {
|
||
+ return EINVAL;
|
||
+ }
|
||
+
|
||
+ at = strchr(full_name, delim);
|
||
+ if (at != NULL) {
|
||
+ s = talloc_strndup(mem_ctx, full_name, (at - full_name));
|
||
+ } else {
|
||
+ s = talloc_strdup(mem_ctx, full_name);
|
||
+ }
|
||
+ if (s == NULL) {
|
||
+ return ENOMEM;
|
||
+ }
|
||
+
|
||
+ *short_name = s;
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static int add_nt_princ_to_san_list(TALLOC_CTX *mem_ctx,
|
||
+ PLArenaPool *pool,
|
||
+ enum san_opt san_opt,
|
||
+ CERTGeneralName *current,
|
||
+ struct san_list **item)
|
||
+{
|
||
+ struct san_list *i = NULL;
|
||
+ SECStatus rv;
|
||
+ SECItem tmp_secitem = { 0 };
|
||
+ int ret;
|
||
+
|
||
+ rv = SEC_ASN1DecodeItem(pool, &tmp_secitem,
|
||
+ SEC_ASN1_GET(SEC_UTF8StringTemplate),
|
||
+ &(current->name.OthName.name));
|
||
+ if (rv != SECSuccess) {
|
||
+ return EINVAL;
|
||
+ }
|
||
+
|
||
+ i = talloc_zero(mem_ctx, struct san_list);
|
||
+ if (i == NULL) {
|
||
+ return ENOMEM;
|
||
+ }
|
||
+ i->san_opt = san_opt;
|
||
+
|
||
+ i->val = talloc_strndup(i, (char *) tmp_secitem.data,
|
||
+ tmp_secitem.len);
|
||
+ if (i->val == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ ret = get_short_name(i, i->val, '@', &(i->short_name));
|
||
+ if (ret != 0) {
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ ret = 0;
|
||
+
|
||
+done:
|
||
+ if (ret == 0) {
|
||
+ *item = i;
|
||
+ } else {
|
||
+ talloc_free(i);
|
||
+ }
|
||
+
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+static int add_pkinit_princ_to_san_list(TALLOC_CTX *mem_ctx,
|
||
+ PLArenaPool *pool,
|
||
+ enum san_opt san_opt,
|
||
+ CERTGeneralName *current,
|
||
+ struct san_list **item)
|
||
+{
|
||
+ struct san_list *i = NULL;
|
||
+ SECStatus rv;
|
||
+ struct kerberos_principal_name kname;
|
||
+ int ret;
|
||
+ size_t c;
|
||
+
|
||
+ rv = SEC_ASN1DecodeItem(pool, &kname,
|
||
+ kerberos_principal_name_template,
|
||
+ &(current->name.OthName.name));
|
||
+ if (rv != SECSuccess) {
|
||
+ return EINVAL;
|
||
+ }
|
||
+
|
||
+ i = talloc_zero(mem_ctx, struct san_list);
|
||
+ if (i == NULL) {
|
||
+ return ENOMEM;
|
||
+ }
|
||
+ i->san_opt = san_opt;
|
||
+
|
||
+ if (kname.principal_name.name_string != NULL) {
|
||
+ i->val = talloc_strdup(i, "");
|
||
+ if (i->val == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+ for (c = 0; kname.principal_name.name_string[c] != NULL; c++) {
|
||
+ if (c > 0) {
|
||
+ i->val = talloc_strdup_append(i->val, "/");
|
||
+ if (i->val == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+ }
|
||
+ i->val = talloc_strndup_append(i->val,
|
||
+ (char *) kname.principal_name.name_string[c]->data,
|
||
+ kname.principal_name.name_string[c]->len);
|
||
+ if (i->val == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+ }
|
||
+ i->val = talloc_strndup_append(i->val,
|
||
+ (char *) kname.realm.data,
|
||
+ kname.realm.len);
|
||
+ if (i->val == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ ret = get_short_name(i, i->val, '@', &(i->short_name));
|
||
+ if (ret != 0) {
|
||
+ goto done;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ ret = 0;
|
||
+
|
||
+done:
|
||
+ if (ret == 0) {
|
||
+ *item = i;
|
||
+ } else {
|
||
+ talloc_free(i);
|
||
+ }
|
||
+
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+static int add_oid_to_san_list(TALLOC_CTX *mem_ctx,
|
||
+ enum san_opt san_opt,
|
||
+ SECItem oid,
|
||
+ struct san_list **item)
|
||
+{
|
||
+ struct san_list *i = NULL;
|
||
+ char *tmp_str;
|
||
+
|
||
+ tmp_str = CERT_GetOidString(&oid);
|
||
+ /* is it expexted that NSS OID strings start with "OID." but we
|
||
+ * prefer the plain dotted-decimal version so the prefix is skipped */
|
||
+ if (tmp_str == NULL || strncmp(tmp_str, "OID.", 4) != 0) {
|
||
+ PR_smprintf_free(tmp_str);
|
||
+ return EINVAL;
|
||
+ }
|
||
+
|
||
+ i = talloc_zero(mem_ctx, struct san_list);
|
||
+ if (i == NULL) {
|
||
+ PR_smprintf_free(tmp_str);
|
||
+ return ENOMEM;
|
||
+ }
|
||
+ i->san_opt = san_opt;
|
||
+
|
||
+ i->val = talloc_strdup(i, tmp_str + 4);
|
||
+ PR_smprintf_free(tmp_str);
|
||
+ if (i->val == NULL) {
|
||
+ talloc_free(i);
|
||
+ return ENOMEM;
|
||
+ }
|
||
+
|
||
+ *item = i;
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static int add_rdn_list_to_san_list(TALLOC_CTX *mem_ctx,
|
||
+ enum san_opt san_opt,
|
||
+ CERTName name,
|
||
+ struct san_list **item)
|
||
+{
|
||
+ struct san_list *i = NULL;
|
||
+ int ret;
|
||
+
|
||
+ i = talloc_zero(mem_ctx, struct san_list);
|
||
+ if (i == NULL) {
|
||
+ return ENOMEM;
|
||
+ }
|
||
+ i->san_opt = san_opt;
|
||
+
|
||
+ ret = get_rdn_list(i, name.rdns, &(i->rdn_list));
|
||
+ if (ret != 0) {
|
||
+ talloc_free(i);
|
||
+ return ret;
|
||
+ }
|
||
+
|
||
+ *item = i;
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static int add_ip_to_san_list(TALLOC_CTX *mem_ctx, enum san_opt san_opt,
|
||
+ uint8_t *data, size_t len,
|
||
+ struct san_list **item)
|
||
+{
|
||
+ struct san_list *i;
|
||
+ PRStatus st;
|
||
+ PRNetAddr addr;
|
||
+ char addrBuf[80];
|
||
+
|
||
+ if (data == NULL || len == 0 || san_opt == SAN_INVALID) {
|
||
+ return EINVAL;
|
||
+ }
|
||
+
|
||
+ /* taken from secu_PrintIPAddress() */
|
||
+ memset(&addr, 0, sizeof addr);
|
||
+ if (len == 4) {
|
||
+ addr.inet.family = PR_AF_INET;
|
||
+ memcpy(&addr.inet.ip, data, len);
|
||
+ } else if (len == 16) {
|
||
+ addr.ipv6.family = PR_AF_INET6;
|
||
+ memcpy(addr.ipv6.ip.pr_s6_addr, data, len);
|
||
+ if (PR_IsNetAddrType(&addr, PR_IpAddrV4Mapped)) {
|
||
+ /* convert to IPv4. */
|
||
+ addr.inet.family = PR_AF_INET;
|
||
+ memcpy(&addr.inet.ip, &addr.ipv6.ip.pr_s6_addr[12], 4);
|
||
+ memset(&addr.inet.pad[0], 0, sizeof addr.inet.pad);
|
||
+ }
|
||
+ } else {
|
||
+ return EINVAL;
|
||
+ }
|
||
+
|
||
+ st = PR_NetAddrToString(&addr, addrBuf, sizeof addrBuf);
|
||
+ if (st != PR_SUCCESS) {
|
||
+ return EIO;
|
||
+ }
|
||
+
|
||
+ i = talloc_zero(mem_ctx, struct san_list);
|
||
+ if (i == NULL) {
|
||
+ return ENOMEM;
|
||
+ }
|
||
+
|
||
+ i->san_opt = san_opt;
|
||
+ i->val = talloc_strdup(i, addrBuf);
|
||
+ if (i->val == NULL) {
|
||
+ talloc_free(i);
|
||
+ return ENOMEM;
|
||
+ }
|
||
+
|
||
+ *item = i;
|
||
+ return 0;
|
||
+}
|
||
+static int add_principal_to_san_list(TALLOC_CTX *mem_ctx,
|
||
+ enum san_opt san_opt,
|
||
+ const char *princ,
|
||
+ struct san_list **item)
|
||
+{
|
||
+ struct san_list *i = NULL;
|
||
+ int ret;
|
||
+
|
||
+ i = talloc_zero(mem_ctx, struct san_list);
|
||
+ if (i == NULL) {
|
||
+ return ENOMEM;
|
||
+ }
|
||
+ i->san_opt = san_opt;
|
||
+
|
||
+ i->val = talloc_strdup(i, princ);
|
||
+ if (i->val == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ ret = get_short_name(i, i->val, '@', &(i->short_name));
|
||
+ if (ret != 0) {
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ ret = 0;
|
||
+
|
||
+done:
|
||
+ if (ret == 0) {
|
||
+ *item = i;
|
||
+ } else {
|
||
+ talloc_free(i);
|
||
+ }
|
||
+
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+static int get_san(TALLOC_CTX *mem_ctx, CERTCertificate *cert,
|
||
+ struct san_list **san_list)
|
||
+{
|
||
+
|
||
+ SECItem subAltName = { 0 };
|
||
+ SECStatus rv;
|
||
+ CERTGeneralName *name_list = NULL;
|
||
+ CERTGeneralName *current;
|
||
+ PLArenaPool *pool = NULL;
|
||
+ int ret;
|
||
+ struct san_list *list = NULL;
|
||
+ struct san_list *item = NULL;
|
||
+ struct san_list *item_s = NULL;
|
||
+ struct san_list *item_p = NULL;
|
||
+ struct san_list *item_pb = NULL;
|
||
+
|
||
+ rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME,
|
||
+ &subAltName);
|
||
+ if (rv != SECSuccess) {
|
||
+ if (rv == SECFailure
|
||
+ && PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND) {
|
||
+ ret = EOK;
|
||
+ } else {
|
||
+ ret = EIO;
|
||
+ }
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
||
+ if (pool == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ name_list = CERT_DecodeAltNameExtension(pool, &subAltName);
|
||
+ if (name_list == NULL ) {
|
||
+ ret = EIO;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ current = name_list;
|
||
+ do {
|
||
+ switch (current->type) {
|
||
+ case certOtherName:
|
||
+ ret = add_string_other_name_to_san_list(mem_ctx,
|
||
+ SAN_STRING_OTHER_NAME,
|
||
+ current, &item_s);
|
||
+ if (ret != 0) {
|
||
+ goto done;
|
||
+ }
|
||
+ DLIST_ADD(list, item_s);
|
||
+
|
||
+ item_p = NULL;
|
||
+ if (strcmp(item_s->other_name_oid, NT_PRINCIPAL_OID) == 0) {
|
||
+ ret = add_nt_princ_to_san_list(mem_ctx, pool, SAN_NT, current,
|
||
+ &item_p);
|
||
+ if (ret != 0) {
|
||
+ goto done;
|
||
+ }
|
||
+ DLIST_ADD(list, item_p);
|
||
+ } else if (strcmp(item_s->other_name_oid, PKINIT_OID) == 0) {
|
||
+ ret = add_pkinit_princ_to_san_list(mem_ctx, pool, SAN_PKINIT,
|
||
+ current, &item_p);
|
||
+ if (ret != 0) {
|
||
+ goto done;
|
||
+ }
|
||
+ DLIST_ADD(list, item_p);
|
||
+ }
|
||
+
|
||
+ if (item_p != NULL) {
|
||
+ ret = add_principal_to_san_list(mem_ctx, SAN_PRINCIPAL,
|
||
+ item_p->val, &item_pb);
|
||
+ if (ret != 0) {
|
||
+ goto done;
|
||
+ }
|
||
+ DLIST_ADD(list, item_pb);
|
||
+ }
|
||
+
|
||
+ break;
|
||
+ case certRFC822Name:
|
||
+ case certDNSName:
|
||
+ case certURI:
|
||
+ ret = add_to_san_list(mem_ctx, false,
|
||
+ nss_name_type_to_san_opt(current->type),
|
||
+ current->name.other.data,
|
||
+ current->name.other.len, &item);
|
||
+ if (ret != 0) {
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ if (current->type == certRFC822Name
|
||
+ || current->type == certDNSName) {
|
||
+ ret = get_short_name(item, item->val,
|
||
+ (current->type == certRFC822Name
|
||
+ ? '@' : '.'),
|
||
+ &(item->short_name));
|
||
+ if (ret != 0) {
|
||
+ goto done;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ DLIST_ADD(list, item);
|
||
+ break;
|
||
+ case certIPAddress:
|
||
+ ret = add_ip_to_san_list(mem_ctx,
|
||
+ nss_name_type_to_san_opt(current->type),
|
||
+ current->name.other.data,
|
||
+ current->name.other.len, &item);
|
||
+ if (ret != 0) {
|
||
+ goto done;
|
||
+ }
|
||
+ DLIST_ADD(list, item);
|
||
+ break;
|
||
+ case certDirectoryName:
|
||
+ ret = add_rdn_list_to_san_list(mem_ctx,
|
||
+ nss_name_type_to_san_opt(current->type),
|
||
+ current->name.directoryName, &item);
|
||
+ if (ret != 0) {
|
||
+ goto done;
|
||
+ }
|
||
+ DLIST_ADD(list, item);
|
||
+ break;
|
||
+ case certRegisterID:
|
||
+ ret = add_oid_to_san_list(mem_ctx,
|
||
+ nss_name_type_to_san_opt(current->type),
|
||
+ current->name.other, &item);
|
||
+ if (ret != 0) {
|
||
+ goto done;
|
||
+ }
|
||
+ DLIST_ADD(list, item);
|
||
+ break;
|
||
+ case certX400Address:
|
||
+ case certEDIPartyName:
|
||
+ ret = add_to_san_list(mem_ctx, true,
|
||
+ nss_name_type_to_san_opt(current->type),
|
||
+ current->name.other.data,
|
||
+ current->name.other.len, &item);
|
||
+ if (ret != 0) {
|
||
+ goto done;
|
||
+ }
|
||
+ DLIST_ADD(list, item);
|
||
+ break;
|
||
+ default:
|
||
+ ret = EINVAL;
|
||
+ }
|
||
+
|
||
+ current = CERT_GetNextGeneralName(current);
|
||
+ if (current == NULL) {
|
||
+ ret = EIO;
|
||
+ goto done;
|
||
+ }
|
||
+ } while (current != name_list);
|
||
+
|
||
+done:
|
||
+
|
||
+ /* Don't free nameList, it's part of the arena. */
|
||
+
|
||
+ if (pool != NULL) {
|
||
+ PORT_FreeArena(pool, PR_FALSE);
|
||
+ }
|
||
+
|
||
+ if (subAltName.data != NULL) {
|
||
+ SECITEM_FreeItem(&subAltName, PR_FALSE);
|
||
+ }
|
||
+
|
||
+ if (ret == EOK) {
|
||
+ *san_list = list;
|
||
+ }
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+int sss_cert_get_content(TALLOC_CTX *mem_ctx,
|
||
+ const uint8_t *der_blob, size_t der_size,
|
||
+ struct sss_cert_content **content)
|
||
+{
|
||
+ int ret;
|
||
+ struct sss_cert_content *cont = NULL;
|
||
+ CERTCertDBHandle *handle;
|
||
+ CERTCertificate *cert = NULL;
|
||
+ SECItem der_item;
|
||
+ NSSInitContext *nss_ctx;
|
||
+
|
||
+ if (der_blob == NULL || der_size == 0) {
|
||
+ return EINVAL;
|
||
+ }
|
||
+
|
||
+ nss_ctx = NSS_InitContext("", "", "", "", NULL, NSS_INIT_READONLY
|
||
+ | NSS_INIT_NOCERTDB
|
||
+ | NSS_INIT_NOMODDB
|
||
+ | NSS_INIT_FORCEOPEN
|
||
+ | NSS_INIT_NOROOTINIT
|
||
+ | NSS_INIT_OPTIMIZESPACE);
|
||
+ if (nss_ctx == NULL) {
|
||
+ return EIO;
|
||
+ }
|
||
+
|
||
+ cont = talloc_zero(mem_ctx, struct sss_cert_content);
|
||
+ if (cont == NULL) {
|
||
+ return ENOMEM;
|
||
+ }
|
||
+
|
||
+ handle = CERT_GetDefaultCertDB();
|
||
+ der_item.len = der_size;
|
||
+ der_item.data = discard_const(der_blob);
|
||
+
|
||
+ cert = CERT_NewTempCertificate(handle, &der_item, NULL, PR_FALSE, PR_TRUE);
|
||
+ if (cert == NULL) {
|
||
+ ret = EINVAL;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ cont->issuer_str = talloc_strdup(cont, cert->issuerName);
|
||
+ if (cont->issuer_str == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ ret = get_rdn_list(cont, cert->issuer.rdns, &cont->issuer_rdn_list);
|
||
+ if (ret != 0) {
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ cont->subject_str = talloc_strdup(cont, cert->subjectName);
|
||
+ if (cont->subject_str == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ ret = get_rdn_list(cont, cert->subject.rdns, &cont->subject_rdn_list);
|
||
+ if (ret != 0) {
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+
|
||
+ cont->key_usage = cert->keyUsage;
|
||
+
|
||
+ ret = get_extended_key_usage_oids(cont, cert,
|
||
+ &(cont->extended_key_usage_oids));
|
||
+ if (ret != 0) {
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ ret = get_san(cont, cert, &(cont->san_list));
|
||
+ if (ret != 0) {
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ cont->cert_der = talloc_memdup(cont, der_blob, der_size);
|
||
+ if (cont->cert_der == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ cont->cert_der_size = der_size;
|
||
+ ret = EOK;
|
||
+
|
||
+done:
|
||
+
|
||
+ CERT_DestroyCertificate(cert);
|
||
+ NSS_ShutdownContext(nss_ctx);
|
||
+
|
||
+ if (ret == EOK) {
|
||
+ *content = cont;
|
||
+ } else {
|
||
+ talloc_free(cont);
|
||
+ }
|
||
+
|
||
+ return ret;
|
||
+}
|
||
diff --git a/src/lib/certmap/sss_certmap.c b/src/lib/certmap/sss_certmap.c
|
||
new file mode 100644
|
||
index 0000000000000000000000000000000000000000..080cab8ab585ce64a88c352a23a8062887fa720a
|
||
--- /dev/null
|
||
+++ b/src/lib/certmap/sss_certmap.c
|
||
@@ -0,0 +1,993 @@
|
||
+/*
|
||
+ SSSD
|
||
+
|
||
+ Library for rule based certificate to user mapping
|
||
+
|
||
+ Authors:
|
||
+ Sumit Bose <sbose@redhat.com>
|
||
+
|
||
+ Copyright (C) 2017 Red Hat
|
||
+
|
||
+ This program is free software; you can redistribute it and/or modify
|
||
+ it under the terms of the GNU General Public License as published by
|
||
+ the Free Software Foundation; either version 3 of the License, or
|
||
+ (at your option) any later version.
|
||
+
|
||
+ This program is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
+ GNU General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU General Public License
|
||
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
+*/
|
||
+
|
||
+#include "util/util.h"
|
||
+#include "util/cert.h"
|
||
+#include "util/crypto/sss_crypto.h"
|
||
+#include "lib/certmap/sss_certmap.h"
|
||
+#include "lib/certmap/sss_certmap_int.h"
|
||
+
|
||
+int debug_level;
|
||
+void sss_debug_fn(const char *file,
|
||
+ long line,
|
||
+ const char *function,
|
||
+ int level,
|
||
+ const char *format, ...)
|
||
+{
|
||
+ return;
|
||
+}
|
||
+
|
||
+static int get_type_prefix(TALLOC_CTX *mem_ctx, const char *match_rule,
|
||
+ char **type, const char **rule_start)
|
||
+{
|
||
+ const char *c;
|
||
+ char *delim;
|
||
+
|
||
+ *type = NULL;
|
||
+ *rule_start = match_rule;
|
||
+
|
||
+ delim = strchr(match_rule, ':');
|
||
+ if (delim == NULL) {
|
||
+ /* no type prefix found */
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ /* rule starts with ':', empty type */
|
||
+ if (delim == match_rule) {
|
||
+ *rule_start = delim + 1;
|
||
+ return EOK;
|
||
+ }
|
||
+
|
||
+ for (c = match_rule; c < delim; c++) {
|
||
+ /* type prefix may only contain digits and upper-case ASCII characters */
|
||
+ if (!(isascii(*c) && (isdigit(*c) || isupper(*c)))) {
|
||
+ /* no type prefix found */
|
||
+ return 0;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ *rule_start = delim + 1;
|
||
+ *type = talloc_strndup(mem_ctx, match_rule, (delim - match_rule));
|
||
+ if (*type == NULL) {
|
||
+ return ENOMEM;
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static int parse_match_rule(struct sss_certmap_ctx *ctx, const char *match_rule,
|
||
+ struct krb5_match_rule **parsed_match_rule)
|
||
+{
|
||
+ int ret;
|
||
+ char *type;
|
||
+ const char *rule_start;
|
||
+
|
||
+ ret = get_type_prefix(ctx, match_rule, &type, &rule_start);
|
||
+ if (ret != EOK) {
|
||
+ CM_DEBUG(ctx, "Failed to read rule type.");
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ if (type == NULL || strcmp(type, "KRB5") == 0) {
|
||
+ ret = parse_krb5_match_rule(ctx, rule_start, parsed_match_rule);
|
||
+ if (ret != EOK) {
|
||
+ CM_DEBUG(ctx, "Failed to parse KRB5 matching rule.");
|
||
+ goto done;
|
||
+ }
|
||
+ } else {
|
||
+ CM_DEBUG(ctx, "Unsupported matching rule type.");
|
||
+ ret = ESRCH;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ ret = EOK;
|
||
+
|
||
+done:
|
||
+ talloc_free(type);
|
||
+
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+static int parse_mapping_rule(struct sss_certmap_ctx *ctx,
|
||
+ const char *mapping_rule,
|
||
+ struct ldap_mapping_rule **parsed_mapping_rule)
|
||
+{
|
||
+ int ret;
|
||
+ char *type;
|
||
+ const char *rule_start;
|
||
+
|
||
+ ret = get_type_prefix(ctx, mapping_rule, &type, &rule_start);
|
||
+ if (ret != EOK) {
|
||
+ CM_DEBUG(ctx, "Failed to read rule type.");
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ if (type == NULL || strcmp(type, "LDAP") == 0) {
|
||
+ ret = parse_ldap_mapping_rule(ctx, rule_start, parsed_mapping_rule);
|
||
+ if (ret != EOK) {
|
||
+ CM_DEBUG(ctx, "Failed to parse LDAP mapping rule.");
|
||
+ goto done;
|
||
+ }
|
||
+ } else {
|
||
+ CM_DEBUG(ctx, "Unsupported mapping rule type.");
|
||
+ ret = ESRCH;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ ret = EOK;
|
||
+
|
||
+done:
|
||
+ talloc_free(type);
|
||
+
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+int sss_certmap_add_rule(struct sss_certmap_ctx *ctx,
|
||
+ uint32_t priority, const char *match_rule,
|
||
+ const char *map_rule, const char **domains)
|
||
+{
|
||
+ size_t c;
|
||
+ int ret;
|
||
+ struct match_map_rule *rule;
|
||
+ struct TALLOC_CTX *tmp_ctx;
|
||
+ struct priority_list *p;
|
||
+ struct priority_list *p_new;
|
||
+ struct krb5_match_rule *parsed_match_rule;
|
||
+ struct ldap_mapping_rule *parsed_mapping_rule;
|
||
+
|
||
+ tmp_ctx = talloc_new(NULL);
|
||
+ if (tmp_ctx == NULL) {
|
||
+ return ENOMEM;
|
||
+ }
|
||
+
|
||
+ rule = talloc_zero(tmp_ctx, struct match_map_rule);
|
||
+ if (rule == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ rule->priority = priority;
|
||
+
|
||
+ if (match_rule == NULL) {
|
||
+ match_rule = DEFAULT_MATCH_RULE;
|
||
+ }
|
||
+ ret = parse_match_rule(ctx, match_rule, &parsed_match_rule);
|
||
+ if (ret == 0) {
|
||
+ rule->parsed_match_rule = talloc_steal(rule, parsed_match_rule);
|
||
+ rule->match_rule = talloc_strdup(rule, match_rule);
|
||
+ if (rule->match_rule == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+ } else if (ret == ESRCH) {
|
||
+ /* report unsupported rules */
|
||
+ goto done;
|
||
+ } else {
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ if (map_rule == NULL) {
|
||
+ map_rule = DEFAULT_MAP_RULE;
|
||
+ }
|
||
+ ret = parse_mapping_rule(ctx, map_rule, &parsed_mapping_rule);
|
||
+ if (ret == 0) {
|
||
+ rule->parsed_mapping_rule = talloc_steal(rule, parsed_mapping_rule);
|
||
+ rule->map_rule = talloc_strdup(rule, map_rule);
|
||
+ if (rule->map_rule == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+ } else if (ret == ESRCH) {
|
||
+ /* report unsupported rules */
|
||
+ goto done;
|
||
+ } else {
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ if (domains != NULL && *domains != NULL) {
|
||
+ for (c = 0; domains[c] != NULL; c++);
|
||
+ rule->domains = talloc_zero_array(rule, char *, c + 1);
|
||
+ if (rule->domains == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+ for (c = 0; domains[c] != NULL; c++) {
|
||
+ rule->domains[c] = talloc_strdup(rule->domains, domains[c]);
|
||
+ if (rule->domains[c] == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (ctx->prio_list == NULL) {
|
||
+ ctx->prio_list = talloc_zero(ctx, struct priority_list);
|
||
+ if (ctx->prio_list == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ ctx->prio_list->priority = rule->priority;
|
||
+ ctx->prio_list->rule_list = rule;
|
||
+ } else {
|
||
+ for (p = ctx->prio_list; p != NULL && p->priority < rule->priority;
|
||
+ p = p->next);
|
||
+ if (p != NULL && p->priority == priority) {
|
||
+ DLIST_ADD(p->rule_list, rule);
|
||
+ } else {
|
||
+ p_new = talloc_zero(ctx, struct priority_list);
|
||
+ if (p_new == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ p_new->priority = rule->priority;
|
||
+ p_new->rule_list = rule;
|
||
+
|
||
+ if (p == NULL) {
|
||
+ DLIST_ADD_END(ctx->prio_list, p_new, struct priority_list *);
|
||
+ } else if (p->prev == NULL) {
|
||
+ DLIST_ADD(ctx->prio_list, p_new);
|
||
+ } else {
|
||
+ DLIST_ADD_AFTER(ctx->prio_list, p_new, p->prev);
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ talloc_steal(ctx, rule);
|
||
+
|
||
+ ret = EOK;
|
||
+
|
||
+done:
|
||
+ talloc_free(tmp_ctx);
|
||
+
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+static int expand_cert(struct sss_certmap_ctx *ctx,
|
||
+ struct parsed_template *parsed_template,
|
||
+ struct sss_cert_content *cert_content,
|
||
+ char **expanded)
|
||
+{
|
||
+ int ret;
|
||
+ char *tmp_str = NULL;
|
||
+
|
||
+ if (parsed_template->conversion == NULL
|
||
+ || strcmp(parsed_template->conversion, "bin") == 0) {
|
||
+ ret = bin_to_ldap_filter_value(ctx, cert_content->cert_der,
|
||
+ cert_content->cert_der_size, &tmp_str);
|
||
+ if (ret != 0) {
|
||
+ CM_DEBUG(ctx, "bin conversion failed.");
|
||
+ goto done;
|
||
+ }
|
||
+ } else if (strcmp(parsed_template->conversion, "base64") == 0) {
|
||
+ tmp_str = sss_base64_encode(ctx, cert_content->cert_der,
|
||
+ cert_content->cert_der_size);
|
||
+ if (tmp_str == NULL) {
|
||
+ CM_DEBUG(ctx, "base64 conversion failed.");
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+ } else {
|
||
+ CM_DEBUG(ctx, "Unsupported conversion.");
|
||
+ ret = EINVAL;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ ret = 0;
|
||
+
|
||
+done:
|
||
+ if (ret == 0) {
|
||
+ *expanded = tmp_str;
|
||
+ } else {
|
||
+ talloc_free(tmp_str);
|
||
+ }
|
||
+
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+static int get_dn_str(struct sss_certmap_ctx *ctx, const char *conversion,
|
||
+ const char **rdn_list, char **result)
|
||
+{
|
||
+ char *str = NULL;
|
||
+ size_t c;
|
||
+ int ret;
|
||
+ char *conv = NULL;
|
||
+
|
||
+ str = talloc_strdup(ctx, "");
|
||
+ if (str == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+ if (conversion == NULL || strcmp(conversion, "nss_ldap") == 0
|
||
+ || strcmp(conversion, "nss") == 0) {
|
||
+ for (c = 0; rdn_list[c] != NULL; c++);
|
||
+ while (c != 0) {
|
||
+ c--;
|
||
+ str = talloc_asprintf_append(str, "%s%s",
|
||
+ (rdn_list[c + 1] == NULL) ? "" : ",",
|
||
+ rdn_list[c]);
|
||
+ if (str == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+ };
|
||
+ } else if (strcmp(conversion, "ad_ldap") == 0) {
|
||
+ for (c = 0; rdn_list[c] != NULL; c++);
|
||
+ while (c != 0) {
|
||
+ c--;
|
||
+ conv = check_ad_attr_name(str, rdn_list[c]);
|
||
+ str = talloc_asprintf_append(str, "%s%s",
|
||
+ (rdn_list[c + 1] == NULL) ? "" : ",",
|
||
+ conv == NULL ? rdn_list[c] : conv);
|
||
+ talloc_free(conv);
|
||
+ conv = NULL;
|
||
+ if (str == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+ };
|
||
+ } else if (strcmp(conversion, "nss_x500") == 0) {
|
||
+ for (c = 0; rdn_list[c] != NULL; c++) {
|
||
+ str = talloc_asprintf_append(str, "%s%s", (c == 0) ? "" : ",",
|
||
+ rdn_list[c]);
|
||
+ if (str == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+ }
|
||
+ } else if (strcmp(conversion, "ad_x500") == 0
|
||
+ || strcmp(conversion, "ad") == 0) {
|
||
+ for (c = 0; rdn_list[c] != NULL; c++) {
|
||
+ conv = check_ad_attr_name(str, rdn_list[c]);
|
||
+ str = talloc_asprintf_append(str, "%s%s",
|
||
+ (c == 0) ? "" : ",",
|
||
+ conv == NULL ? rdn_list[c] : conv);
|
||
+ talloc_free(conv);
|
||
+ conv = NULL;
|
||
+ if (str == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+ }
|
||
+ } else {
|
||
+ ret = EINVAL;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ ret = 0;
|
||
+
|
||
+done:
|
||
+ if (ret == 0) {
|
||
+ *result = str;
|
||
+ } else {
|
||
+ talloc_free(str);
|
||
+ }
|
||
+
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+static int expand_san_blob(struct sss_certmap_ctx *ctx, enum san_opt san_opt,
|
||
+ struct san_list *san_list, char **expanded)
|
||
+{
|
||
+ struct san_list *item;
|
||
+ char *exp;
|
||
+ int ret;
|
||
+
|
||
+ DLIST_FOR_EACH(item, san_list) {
|
||
+ if (item->san_opt == san_opt) {
|
||
+ ret = bin_to_ldap_filter_value(ctx, item->bin_val,
|
||
+ item->bin_val_len, &exp);
|
||
+ if (ret != 0) {
|
||
+ CM_DEBUG(ctx, "bin conversion failed.");
|
||
+ return ret;
|
||
+ }
|
||
+
|
||
+ *expanded = exp;
|
||
+ return 0;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return ENOENT;
|
||
+}
|
||
+
|
||
+static int expand_san_string(struct sss_certmap_ctx *ctx, enum san_opt san_opt,
|
||
+ struct san_list *san_list, const char *attr_name,
|
||
+ char **expanded)
|
||
+{
|
||
+ struct san_list *item;
|
||
+ char *exp;
|
||
+
|
||
+ DLIST_FOR_EACH(item, san_list) {
|
||
+ if (item->san_opt == san_opt) {
|
||
+ if (attr_name == NULL) {
|
||
+ exp = talloc_strdup(ctx, item->val);
|
||
+ } else if (strcasecmp(attr_name, "short_name") == 0) {
|
||
+ exp = talloc_strdup(ctx, item->short_name);
|
||
+ } else {
|
||
+ CM_DEBUG(ctx, "Unsupported attribute name [%s].", attr_name);
|
||
+ return EINVAL;
|
||
+ }
|
||
+
|
||
+ if (exp == NULL) {
|
||
+ return ENOMEM;
|
||
+ }
|
||
+
|
||
+ *expanded = exp;
|
||
+ return 0;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return ENOENT;
|
||
+}
|
||
+
|
||
+static int expand_san_rdn_list(struct sss_certmap_ctx *ctx,
|
||
+ enum san_opt san_opt,
|
||
+ struct san_list *san_list,
|
||
+ const char *conversion,
|
||
+ char **expanded)
|
||
+{
|
||
+ struct san_list *item;
|
||
+ char *exp;
|
||
+ int ret;
|
||
+
|
||
+ DLIST_FOR_EACH(item, san_list) {
|
||
+ if (item->san_opt == san_opt) {
|
||
+ ret = get_dn_str(ctx, conversion, item->rdn_list, &exp);
|
||
+ if (ret != 0) {
|
||
+ return ret;
|
||
+ }
|
||
+
|
||
+ *expanded = exp;
|
||
+ return 0;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return ENOENT;
|
||
+}
|
||
+
|
||
+
|
||
+static int expand_san(struct sss_certmap_ctx *ctx,
|
||
+ struct parsed_template *parsed_template,
|
||
+ struct san_list *san_list,
|
||
+ char **expanded)
|
||
+{
|
||
+ int ret;
|
||
+
|
||
+ if (strcmp("subject_rfc822_name", parsed_template->name) == 0) {
|
||
+ ret = expand_san_string(ctx, SAN_RFC822_NAME, san_list,
|
||
+ parsed_template->attr_name, expanded);
|
||
+ } else if (strcmp("subject_dns_name", parsed_template->name) == 0) {
|
||
+ ret = expand_san_string(ctx, SAN_DNS_NAME, san_list,
|
||
+ parsed_template->attr_name, expanded);
|
||
+ } else if (strcmp("subject_x400_address", parsed_template->name) == 0) {
|
||
+ ret = expand_san_blob(ctx, SAN_X400_ADDRESS, san_list, expanded);
|
||
+ } else if (strcmp("subject_directory_name", parsed_template->name) == 0) {
|
||
+ ret = expand_san_rdn_list(ctx, SAN_DIRECTORY_NAME, san_list,
|
||
+ parsed_template->conversion, expanded);
|
||
+ } else if (strcmp("subject_ediparty_name", parsed_template->name) == 0) {
|
||
+ ret = expand_san_blob(ctx, SAN_EDIPART_NAME, san_list, expanded);
|
||
+ } else if (strcmp("subject_uri", parsed_template->name) == 0) {
|
||
+ ret = expand_san_string(ctx, SAN_URI, san_list,
|
||
+ parsed_template->attr_name, expanded);
|
||
+ } else if (strcmp("subject_ip_address", parsed_template->name) == 0) {
|
||
+ ret = expand_san_string(ctx, SAN_IP_ADDRESS, san_list,
|
||
+ parsed_template->attr_name, expanded);
|
||
+ } else if (strcmp("subject_registered_id", parsed_template->name) == 0) {
|
||
+ ret = expand_san_string(ctx, SAN_REGISTERED_ID, san_list,
|
||
+ parsed_template->attr_name, expanded);
|
||
+ } else if (strcmp("subject_pkinit_principal", parsed_template->name) == 0) {
|
||
+ ret = expand_san_string(ctx, SAN_PKINIT, san_list,
|
||
+ parsed_template->attr_name, expanded);
|
||
+ } else if (strcmp("subject_nt_principal", parsed_template->name) == 0) {
|
||
+ ret = expand_san_string(ctx, SAN_NT, san_list,
|
||
+ parsed_template->attr_name, expanded);
|
||
+ } else if (strcmp("subject_principal", parsed_template->name) == 0) {
|
||
+ ret = expand_san_string(ctx, SAN_PRINCIPAL, san_list,
|
||
+ parsed_template->attr_name, expanded);
|
||
+ } else {
|
||
+ CM_DEBUG(ctx, "Unsupported template name [%s].n",
|
||
+ parsed_template->name);
|
||
+ ret = EINVAL;
|
||
+ }
|
||
+
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+static int expand_template(struct sss_certmap_ctx *ctx,
|
||
+ struct parsed_template *parsed_template,
|
||
+ struct sss_cert_content *cert_content,
|
||
+ char **expanded)
|
||
+{
|
||
+ int ret;
|
||
+ char *exp = NULL;
|
||
+
|
||
+ if (strcmp("issuer_dn", parsed_template->name) == 0) {
|
||
+ ret = get_dn_str(ctx, parsed_template->conversion,
|
||
+ cert_content->issuer_rdn_list, &exp);
|
||
+ } else if (strcmp("subject_dn", parsed_template->name) == 0) {
|
||
+ ret = get_dn_str(ctx, parsed_template->conversion,
|
||
+ cert_content->subject_rdn_list, &exp);
|
||
+ } else if (strncmp("subject_", parsed_template->name, 8) == 0) {
|
||
+ ret = expand_san(ctx, parsed_template, cert_content->san_list, &exp);
|
||
+ } else if (strcmp("cert", parsed_template->name) == 0) {
|
||
+ ret = expand_cert(ctx, parsed_template, cert_content, &exp);
|
||
+ } else {
|
||
+ CM_DEBUG(ctx, "Unsupported template name.");
|
||
+ ret = EINVAL;
|
||
+ goto done;
|
||
+ }
|
||
+ if (ret != 0) {
|
||
+ CM_DEBUG(ctx, "Failed to expand [%s] template.", parsed_template->name);
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ if (exp == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ ret = 0;
|
||
+
|
||
+done:
|
||
+ if (ret == 0) {
|
||
+ *expanded = exp;
|
||
+ } else {
|
||
+ talloc_free(exp);
|
||
+ }
|
||
+
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+static int get_filter(struct sss_certmap_ctx *ctx,
|
||
+ struct ldap_mapping_rule *parsed_mapping_rule,
|
||
+ struct sss_cert_content *cert_content,
|
||
+ char **filter)
|
||
+{
|
||
+ struct ldap_mapping_rule_comp *comp;
|
||
+ char *result = NULL;
|
||
+ char *expanded = NULL;
|
||
+ int ret;
|
||
+
|
||
+ result = talloc_strdup(ctx, "");
|
||
+ if (result == NULL) {
|
||
+ return ENOMEM;
|
||
+ }
|
||
+
|
||
+ for (comp = parsed_mapping_rule->list; comp != NULL; comp = comp->next) {
|
||
+ if (comp->type == comp_string) {
|
||
+ result = talloc_strdup_append(result, comp->val);
|
||
+ } else if (comp->type == comp_template) {
|
||
+ ret = expand_template(ctx, comp->parsed_template, cert_content,
|
||
+ &expanded);
|
||
+ if (ret != 0) {
|
||
+ CM_DEBUG(ctx, "Failed to expanded template.");
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ result = talloc_strdup_append(result, expanded);
|
||
+ talloc_free(expanded);
|
||
+ expanded = NULL;
|
||
+ if (result == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+ } else {
|
||
+ ret = EINVAL;
|
||
+ CM_DEBUG(ctx, "Unsupported component type.");
|
||
+ goto done;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ ret = 0;
|
||
+done:
|
||
+ talloc_free(expanded);
|
||
+ if (ret == 0) {
|
||
+ *filter = result;
|
||
+ } else {
|
||
+ talloc_free(result);
|
||
+ }
|
||
+
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+static bool check_san_regexp(struct sss_certmap_ctx *ctx,
|
||
+ enum san_opt san_opt, regex_t regexp,
|
||
+ struct san_list *san_list)
|
||
+{
|
||
+ struct san_list *item;
|
||
+ bool match = false;
|
||
+ int ret;
|
||
+ char *tmp_str = NULL;
|
||
+
|
||
+ DLIST_FOR_EACH(item, san_list) {
|
||
+ if (item->san_opt == san_opt) {
|
||
+ if (item->san_opt == SAN_DIRECTORY_NAME) {
|
||
+ /* use LDAP order for matching */
|
||
+ ret = get_dn_str(ctx, NULL, item->rdn_list, &tmp_str);
|
||
+ if (ret != 0 || tmp_str == NULL) {
|
||
+ return false;
|
||
+ }
|
||
+ match = (regexec(®exp, tmp_str, 0, NULL, 0) == 0);
|
||
+ talloc_free(tmp_str);
|
||
+ } else {
|
||
+ match = (item->val != NULL
|
||
+ && regexec(®exp, item->val, 0, NULL, 0) == 0);
|
||
+ }
|
||
+ if (!match) {
|
||
+ return false;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return match;
|
||
+}
|
||
+
|
||
+static bool check_san_blob(enum san_opt san_opt,
|
||
+ uint8_t *bin_val, size_t bin_val_len,
|
||
+ struct san_list *san_list)
|
||
+{
|
||
+ struct san_list *item;
|
||
+ bool match = false;
|
||
+
|
||
+ if (bin_val == NULL || bin_val_len == 0) {
|
||
+ return false;
|
||
+ }
|
||
+
|
||
+ DLIST_FOR_EACH(item, san_list) {
|
||
+ if (item->san_opt == san_opt) {
|
||
+ match = (item->bin_val != NULL && item->bin_val_len != 0
|
||
+ && memmem(item->bin_val, item->bin_val_len,
|
||
+ bin_val, bin_val_len) != NULL);
|
||
+ if (!match) {
|
||
+ return false;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return match;
|
||
+}
|
||
+
|
||
+static bool check_san_str_other_name(enum san_opt san_opt,
|
||
+ const char *str_other_name_oid,
|
||
+ regex_t regexp,
|
||
+ struct san_list *san_list)
|
||
+{
|
||
+ struct san_list *item;
|
||
+ bool match = false;
|
||
+ char *tmp_str;
|
||
+
|
||
+ if (str_other_name_oid == NULL) {
|
||
+ return false;
|
||
+ }
|
||
+
|
||
+ DLIST_FOR_EACH(item, san_list) {
|
||
+ if (item->san_opt == san_opt
|
||
+ && strcmp(item->other_name_oid, str_other_name_oid) == 0) {
|
||
+ match = false;
|
||
+ if (item->bin_val != NULL && item->bin_val_len != 0) {
|
||
+ tmp_str = talloc_strndup(item, (char *) item->bin_val,
|
||
+ item->bin_val_len);
|
||
+ if (tmp_str != NULL) {
|
||
+ match = (regexec(®exp, tmp_str, 0, NULL, 0) == 0);
|
||
+ }
|
||
+ talloc_free(tmp_str);
|
||
+ }
|
||
+ if (!match) {
|
||
+ return false;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return match;
|
||
+}
|
||
+
|
||
+static bool do_san_match(struct sss_certmap_ctx *ctx,
|
||
+ struct component_list *comp,
|
||
+ struct san_list *san_list)
|
||
+{
|
||
+ switch (comp->san_opt) {
|
||
+ case SAN_OTHER_NAME:
|
||
+ return check_san_blob(SAN_STRING_OTHER_NAME,
|
||
+ comp->bin_val, comp->bin_val_len,
|
||
+ san_list);
|
||
+ break;
|
||
+ case SAN_X400_ADDRESS:
|
||
+ case SAN_EDIPART_NAME:
|
||
+ return check_san_blob(comp->san_opt, comp->bin_val, comp->bin_val_len,
|
||
+ san_list);
|
||
+ break;
|
||
+ case SAN_RFC822_NAME:
|
||
+ case SAN_DNS_NAME:
|
||
+ case SAN_DIRECTORY_NAME:
|
||
+ case SAN_URI:
|
||
+ case SAN_IP_ADDRESS:
|
||
+ case SAN_REGISTERED_ID:
|
||
+ case SAN_PKINIT:
|
||
+ case SAN_NT:
|
||
+ case SAN_PRINCIPAL:
|
||
+ return check_san_regexp(ctx, comp->san_opt, comp->regexp, san_list);
|
||
+ break;
|
||
+ case SAN_STRING_OTHER_NAME:
|
||
+ return check_san_str_other_name(comp->san_opt, comp->str_other_name_oid,
|
||
+ comp->regexp, san_list);
|
||
+ break;
|
||
+ default:
|
||
+ CM_DEBUG(ctx, "Unsupported SAN option [%d].", comp->san_opt);
|
||
+ return false;
|
||
+ }
|
||
+}
|
||
+
|
||
+static int do_match(struct sss_certmap_ctx *ctx,
|
||
+ struct krb5_match_rule *parsed_match_rule,
|
||
+ struct sss_cert_content *cert_content)
|
||
+{
|
||
+ struct component_list *comp;
|
||
+ bool match = false;
|
||
+ size_t c;
|
||
+
|
||
+ if (parsed_match_rule == NULL || cert_content == NULL) {
|
||
+ return EINVAL;
|
||
+ }
|
||
+
|
||
+ /* Issuer */
|
||
+ for (comp = parsed_match_rule->issuer; comp != NULL; comp = comp->next) {
|
||
+ match = (cert_content->issuer_str != NULL
|
||
+ && regexec(&(comp->regexp), cert_content->issuer_str,
|
||
+ 0, NULL, 0) == 0);
|
||
+ if (match && parsed_match_rule->r == relation_or) {
|
||
+ /* match */
|
||
+ return 0;
|
||
+ } else if (!match && parsed_match_rule->r == relation_and) {
|
||
+ /* no match */
|
||
+ return ENOENT;
|
||
+ }
|
||
+
|
||
+ }
|
||
+
|
||
+ /* Subject */
|
||
+ for (comp = parsed_match_rule->subject; comp != NULL; comp = comp->next) {
|
||
+ match = (cert_content->subject_str != NULL
|
||
+ && regexec(&(comp->regexp), cert_content->subject_str,
|
||
+ 0, NULL, 0) == 0);
|
||
+ if (match && parsed_match_rule->r == relation_or) {
|
||
+ /* match */
|
||
+ return 0;
|
||
+ } else if (!match && parsed_match_rule->r == relation_and) {
|
||
+ /* no match */
|
||
+ return ENOENT;
|
||
+ }
|
||
+
|
||
+ }
|
||
+
|
||
+ /* Key Usage */
|
||
+ for (comp = parsed_match_rule->ku; comp != NULL; comp = comp->next) {
|
||
+ match = ((cert_content->key_usage & comp->ku) == comp->ku);
|
||
+ if (match && parsed_match_rule->r == relation_or) {
|
||
+ /* match */
|
||
+ return 0;
|
||
+ } else if (!match && parsed_match_rule->r == relation_and) {
|
||
+ /* no match */
|
||
+ return ENOENT;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* Extended Key Usage */
|
||
+ for (comp = parsed_match_rule->eku; comp != NULL; comp = comp->next) {
|
||
+ for (c = 0; comp->eku_oid_list[c] != NULL; c++) {
|
||
+ match = string_in_list(comp->eku_oid_list[c],
|
||
+ discard_const(
|
||
+ cert_content->extended_key_usage_oids),
|
||
+ true);
|
||
+ if (match && parsed_match_rule->r == relation_or) {
|
||
+ /* match */
|
||
+ return 0;
|
||
+ } else if (!match && parsed_match_rule->r == relation_and) {
|
||
+ /* no match */
|
||
+ return ENOENT;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* SAN */
|
||
+ for (comp = parsed_match_rule->san; comp != NULL; comp = comp->next) {
|
||
+ match = do_san_match(ctx, comp, cert_content->san_list);
|
||
+ if (match && parsed_match_rule->r == relation_or) {
|
||
+ /* match */
|
||
+ return 0;
|
||
+ } else if (!match && parsed_match_rule->r == relation_and) {
|
||
+ /* no match */
|
||
+ return ENOENT;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (match) {
|
||
+ /* match */
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ /* no match */
|
||
+ return ENOENT;
|
||
+}
|
||
+
|
||
+int sss_certmap_match_cert(struct sss_certmap_ctx *ctx,
|
||
+ const uint8_t *der_cert, size_t der_size)
|
||
+{
|
||
+ int ret;
|
||
+ struct match_map_rule *r;
|
||
+ struct priority_list *p;
|
||
+ struct sss_cert_content *cert_content = NULL;
|
||
+
|
||
+ ret = sss_cert_get_content(ctx, der_cert, der_size, &cert_content);
|
||
+ if (ret != 0) {
|
||
+ CM_DEBUG(ctx, "Failed to get certificate content.");
|
||
+ return ret;
|
||
+ }
|
||
+
|
||
+ if (ctx->prio_list == NULL) {
|
||
+ /* Match all certificates if there are no rules applied */
|
||
+ ret = 0;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ for (p = ctx->prio_list; p != NULL; p = p->next) {
|
||
+ for (r = p->rule_list; r != NULL; r = r->next) {
|
||
+ ret = do_match(ctx, r->parsed_match_rule, cert_content);
|
||
+ if (ret == 0) {
|
||
+ /* match */
|
||
+ goto done;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ ret = ENOENT;
|
||
+done:
|
||
+ talloc_free(cert_content);
|
||
+
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+int sss_certmap_get_search_filter(struct sss_certmap_ctx *ctx,
|
||
+ const uint8_t *der_cert, size_t der_size,
|
||
+ char **_filter, char ***_domains)
|
||
+{
|
||
+ int ret;
|
||
+ struct match_map_rule *r;
|
||
+ struct priority_list *p;
|
||
+ struct sss_cert_content *cert_content = NULL;
|
||
+ char *filter = NULL;
|
||
+ char **domains = NULL;
|
||
+ size_t c;
|
||
+
|
||
+ if (_filter == NULL || _domains == NULL) {
|
||
+ return EINVAL;
|
||
+ }
|
||
+
|
||
+ ret = sss_cert_get_content(ctx, der_cert, der_size, &cert_content);
|
||
+ if (ret != 0) {
|
||
+ CM_DEBUG(ctx, "Failed to get certificate content [%d].", ret);
|
||
+ return ret;
|
||
+ }
|
||
+
|
||
+ if (ctx->prio_list == NULL) {
|
||
+ if (ctx->default_mapping_rule == NULL) {
|
||
+ CM_DEBUG(ctx, "No matching or mapping rules available.");
|
||
+ return EINVAL;
|
||
+ }
|
||
+
|
||
+ ret = get_filter(ctx, ctx->default_mapping_rule, cert_content, &filter);
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ for (p = ctx->prio_list; p != NULL; p = p->next) {
|
||
+ for (r = p->rule_list; r != NULL; r = r->next) {
|
||
+ ret = do_match(ctx, r->parsed_match_rule, cert_content);
|
||
+ if (ret == 0) {
|
||
+ /* match */
|
||
+ ret = get_filter(ctx, r->parsed_mapping_rule, cert_content,
|
||
+ &filter);
|
||
+ if (ret != 0) {
|
||
+ CM_DEBUG(ctx, "Failed to get filter");
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ if (r->domains != NULL) {
|
||
+ for (c = 0; r->domains[c] != NULL; c++);
|
||
+ domains = talloc_zero_array(ctx, char *, c + 1);
|
||
+ if (domains == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ for (c = 0; r->domains[c] != NULL; c++) {
|
||
+ domains[c] = talloc_strdup(domains, r->domains[c]);
|
||
+ if (domains[c] == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ ret = 0;
|
||
+ goto done;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ ret = ENOENT;
|
||
+
|
||
+done:
|
||
+ talloc_free(cert_content);
|
||
+ if (ret == 0) {
|
||
+ *_filter = filter;
|
||
+ *_domains = domains;
|
||
+ } else {
|
||
+ talloc_free(filter);
|
||
+ talloc_free(domains);
|
||
+ }
|
||
+
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+int sss_certmap_init(TALLOC_CTX *mem_ctx,
|
||
+ sss_certmap_ext_debug *debug, void *debug_priv,
|
||
+ struct sss_certmap_ctx **ctx)
|
||
+{
|
||
+ int ret;
|
||
+
|
||
+ if (ctx == NULL) {
|
||
+ return EINVAL;
|
||
+ }
|
||
+
|
||
+ *ctx = talloc_zero(mem_ctx, struct sss_certmap_ctx);
|
||
+ if (*ctx == NULL) {
|
||
+ return ENOMEM;
|
||
+ }
|
||
+
|
||
+ (*ctx)->debug = debug;
|
||
+ (*ctx)->debug_priv = debug_priv;
|
||
+
|
||
+ ret = parse_mapping_rule(*ctx, DEFAULT_MAP_RULE,
|
||
+ &((*ctx)->default_mapping_rule));
|
||
+ if (ret != 0) {
|
||
+ CM_DEBUG((*ctx), "Failed to parse default mapping rule.");
|
||
+ talloc_free(*ctx);
|
||
+ *ctx = NULL;
|
||
+ return ret;
|
||
+ }
|
||
+
|
||
+ CM_DEBUG((*ctx), "sss_certmap initialized.");
|
||
+ return EOK;
|
||
+}
|
||
+
|
||
+void sss_certmap_free_ctx(struct sss_certmap_ctx *ctx)
|
||
+{
|
||
+ talloc_free(ctx);
|
||
+}
|
||
+
|
||
+void sss_certmap_free_filter_and_domains(char *filter, char **domains)
|
||
+{
|
||
+ talloc_free(filter);
|
||
+ talloc_free(domains);
|
||
+}
|
||
diff --git a/src/lib/certmap/sss_certmap.doxy.in b/src/lib/certmap/sss_certmap.doxy.in
|
||
new file mode 100644
|
||
index 0000000000000000000000000000000000000000..e8959e2099a0f517c314833e47d410306fb02702
|
||
--- /dev/null
|
||
+++ b/src/lib/certmap/sss_certmap.doxy.in
|
||
@@ -0,0 +1,3 @@
|
||
+PROJECT_NAME = sss_certmap
|
||
+OUTPUT_DIRECTORY = certmap_doc
|
||
+INPUT = @abs_top_srcdir@/src/lib/certmap/sss_certmap.h
|
||
diff --git a/src/lib/certmap/sss_certmap.exports b/src/lib/certmap/sss_certmap.exports
|
||
new file mode 100644
|
||
index 0000000000000000000000000000000000000000..8b5d5366697401649547c09c6b6f3db571c2b518
|
||
--- /dev/null
|
||
+++ b/src/lib/certmap/sss_certmap.exports
|
||
@@ -0,0 +1,13 @@
|
||
+SSS_CERTMAP_0.0 {
|
||
+ global:
|
||
+ sss_certmap_init;
|
||
+ sss_certmap_free_ctx;
|
||
+ sss_certmap_err_msg;
|
||
+ sss_certmap_add_rule;
|
||
+ sss_certmap_match_cert;
|
||
+ sss_certmap_get_search_filter;
|
||
+ sss_cert_get_content;
|
||
+ sss_certmap_free_filter_and_domains;
|
||
+ local:
|
||
+ *;
|
||
+};
|
||
diff --git a/src/lib/certmap/sss_certmap.h b/src/lib/certmap/sss_certmap.h
|
||
new file mode 100644
|
||
index 0000000000000000000000000000000000000000..55485cc35e8bd7cf2cb2b0c5a06a7521025e3c43
|
||
--- /dev/null
|
||
+++ b/src/lib/certmap/sss_certmap.h
|
||
@@ -0,0 +1,155 @@
|
||
+/*
|
||
+ SSSD
|
||
+
|
||
+ Library for rule based certificate to user mapping
|
||
+
|
||
+ Authors:
|
||
+ Sumit Bose <sbose@redhat.com>
|
||
+
|
||
+ Copyright (C) 2017 Red Hat
|
||
+
|
||
+ This program is free software; you can redistribute it and/or modify
|
||
+ it under the terms of the GNU General Public License as published by
|
||
+ the Free Software Foundation; either version 3 of the License, or
|
||
+ (at your option) any later version.
|
||
+
|
||
+ This program is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
+ GNU General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU General Public License
|
||
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
+*/
|
||
+
|
||
+#ifndef _SSS_CERTMAP_H_
|
||
+#define _SSS_CERTMAP_H_
|
||
+
|
||
+#include <stdlib.h>
|
||
+#include <stdint.h>
|
||
+#include <stdbool.h>
|
||
+#include <sys/types.h>
|
||
+
|
||
+#include <talloc.h>
|
||
+
|
||
+/**
|
||
+ * @defgroup sss_certmap Allow rule-based mapping of certificates to users
|
||
+ * Libsss_certmap provides a mechanism to map X509 certificate to users based
|
||
+ * on rules.
|
||
+ * @{
|
||
+ */
|
||
+
|
||
+/**
|
||
+ * Opaque type for the idmap context
|
||
+ */
|
||
+struct sss_certmap_ctx;
|
||
+
|
||
+/**
|
||
+ * Lowest priority of a rule
|
||
+ */
|
||
+#define SSS_CERTMAP_MIN_PRIO UINT32_MAX
|
||
+
|
||
+/**
|
||
+ * Typedef for external debug callback
|
||
+ */
|
||
+typedef void (sss_certmap_ext_debug)(void *pvt,
|
||
+ const char *file, long line,
|
||
+ const char *function,
|
||
+ const char *format, ...);
|
||
+/**
|
||
+ * @brief Initialize certmap context
|
||
+ *
|
||
+ * @param[in] mem_ctx Talloc memory context, may be NULL
|
||
+ * @param[in] debug Callback to handle debug output, may be NULL
|
||
+ * @param[in] debug_priv Private data for debugging callback, may be NULL
|
||
+ * @param[out] ctx New certmap context
|
||
+ *
|
||
+ * @return
|
||
+ * - 0: success
|
||
+ * - ENOMEM: failed to allocate internal Talloc context
|
||
+ * - EINVAL: ctx is NULL
|
||
+ */
|
||
+int sss_certmap_init(TALLOC_CTX *mem_ctx,
|
||
+ sss_certmap_ext_debug *debug, void *debug_priv,
|
||
+ struct sss_certmap_ctx **ctx);
|
||
+
|
||
+/**
|
||
+ * @brief Free certmap context
|
||
+ *
|
||
+ * @param[in] ctx certmap context previously initialized with
|
||
+ * @ref sss_certmap_init, may be NULL
|
||
+ */
|
||
+void sss_certmap_free_ctx(struct sss_certmap_ctx *ctx);
|
||
+
|
||
+/**
|
||
+ * @brief Add a rule to the certmap context
|
||
+ *
|
||
+ * @param[in] ctx certmap context previously initialized with
|
||
+ * @ref sss_certmap_init
|
||
+ * @param[in] priority priority of the rule, 0 is the hightest priority, the
|
||
+ * lowest is SSS_CERTMAP_MIN_PRIO
|
||
+ * @param[in] match_rule String with the matching rule
|
||
+ * @param[in] map_rule String with the mapping rule
|
||
+ * @param[in] domains NULL-terminated string array with a list of domains
|
||
+ * the rule should be valid for, i.e. only this domains
|
||
+ * should be searched for matching users
|
||
+ *
|
||
+ * @return
|
||
+ * - 0: success
|
||
+ */
|
||
+int sss_certmap_add_rule(struct sss_certmap_ctx *ctx,
|
||
+ uint32_t priority, const char *match_rule,
|
||
+ const char *map_rule, const char **domains);
|
||
+
|
||
+/**
|
||
+ * @brief Check if a certificate matches any of the applied rules
|
||
+ *
|
||
+ * @param[in] ctx certmap context previously initialized with
|
||
+ * @ref sss_certmap_init
|
||
+ * @param[in] der_cert binary blog with the DER encoded certificate
|
||
+ * @param[in] der_size size of the certificate blob
|
||
+ *
|
||
+ * @return
|
||
+ * - 0: certificate matches a rule
|
||
+ * - ENOENT: certificate does not match
|
||
+ * - EINVAL: internal error
|
||
+ */
|
||
+int sss_certmap_match_cert(struct sss_certmap_ctx *ctx,
|
||
+ const uint8_t *der_cert, size_t der_size);
|
||
+
|
||
+/**
|
||
+ * @brief Get the LDAP filter string for a certificate
|
||
+ *
|
||
+ * @param[in] ctx certmap context previously initialized with
|
||
+ * @ref sss_certmap_init
|
||
+ * @param[in] der_cert binary blog with the DER encoded certificate
|
||
+ * @param[in] der_size size of the certificate blob
|
||
+ * @param[out] filter LDAP filter string, caller should free the data by
|
||
+ * calling sss_certmap_free_filter_and_domains
|
||
+ * @param[out] domains NULL-terminated array of strings with the domains the
|
||
+ * rule applies, caller should free the data by calling
|
||
+ * sss_certmap_free_filter_and_domains
|
||
+ *
|
||
+ * @return
|
||
+ * - 0: certificate matches a rule
|
||
+ * - ENOENT: certificate does not match
|
||
+ * - EINVAL: internal error
|
||
+ */
|
||
+int sss_certmap_get_search_filter(struct sss_certmap_ctx *ctx,
|
||
+ const uint8_t *der_cert, size_t der_size,
|
||
+ char **filter, char ***domains);
|
||
+
|
||
+/**
|
||
+ * @brief Free data returned by @ref sss_certmap_get_search_filter
|
||
+ *
|
||
+ * @param[in] filter LDAP filter strings returned by
|
||
+ * sss_certmap_get_search_filter
|
||
+ * @param[in] domains string array of domains returned by
|
||
+ * sss_certmap_get_search_filter
|
||
+ */
|
||
+void sss_certmap_free_filter_and_domains(char *filter, char **domains);
|
||
+
|
||
+/**
|
||
+ * @}
|
||
+ */
|
||
+#endif /* _SSS_CERTMAP_H_ */
|
||
diff --git a/src/lib/certmap/sss_certmap.pc.in b/src/lib/certmap/sss_certmap.pc.in
|
||
new file mode 100644
|
||
index 0000000000000000000000000000000000000000..f1a4432fce8ccd5642a622ca6a8d3a7954fc7ba3
|
||
--- /dev/null
|
||
+++ b/src/lib/certmap/sss_certmap.pc.in
|
||
@@ -0,0 +1,11 @@
|
||
+prefix=@prefix@
|
||
+exec_prefix=@exec_prefix@
|
||
+libdir=@libdir@
|
||
+includedir=@includedir@
|
||
+
|
||
+Name: sss_certmap
|
||
+Description: SSS certificate mapping library
|
||
+Version: @VERSION@
|
||
+Libs: -L${libdir} -lsss_certmap
|
||
+Cflags:
|
||
+URL: https://pagure.io/SSSD/sssd/
|
||
diff --git a/src/lib/certmap/sss_certmap_attr_names.c b/src/lib/certmap/sss_certmap_attr_names.c
|
||
new file mode 100644
|
||
index 0000000000000000000000000000000000000000..a28a464910728cdd1f316b2b979da84f440685ea
|
||
--- /dev/null
|
||
+++ b/src/lib/certmap/sss_certmap_attr_names.c
|
||
@@ -0,0 +1,107 @@
|
||
+/*
|
||
+ SSSD
|
||
+
|
||
+ Library for rule based certificate to user mapping - Attribute name
|
||
+ mapping for different implementations
|
||
+
|
||
+ Authors:
|
||
+ Sumit Bose <sbose@redhat.com>
|
||
+
|
||
+ Copyright (C) 2017 Red Hat
|
||
+
|
||
+ This program is free software; you can redistribute it and/or modify
|
||
+ it under the terms of the GNU General Public License as published by
|
||
+ the Free Software Foundation; either version 3 of the License, or
|
||
+ (at your option) any later version.
|
||
+
|
||
+ This program is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
+ GNU General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU General Public License
|
||
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
+*/
|
||
+
|
||
+/* NSS data taken from nss-utils:nss/lib/util/secoid.c and
|
||
+ * nss:nss/lib/certdb/alg1485.c */
|
||
+
|
||
+/* AD data taken from
|
||
+ * https://msdn.microsoft.com/en-us/library/windows/desktop/aa376556%28v=vs.85%29.aspx
|
||
+ * and wine source code dlls/crypt32/oid.c and include/wincrypt.h . */
|
||
+
|
||
+#include <stdbool.h>
|
||
+#include <string.h>
|
||
+#include <talloc.h>
|
||
+
|
||
+struct oid_attr_name_map {
|
||
+ bool nss_ad_differ;
|
||
+ const char *oid;
|
||
+ const char *nss;
|
||
+ const char *ad;
|
||
+} oid_attr_name_map[] = {
|
||
+ { false, "2.5.4.3", "CN", "CN"},
|
||
+ { true, "2.5.4.8", "ST", "S"},
|
||
+ { false, "2.5.4.10", "O", "O"},
|
||
+ { false, "2.5.4.11", "OU", "OU"},
|
||
+ { false, "2.5.4.46", "dnQualifier", "dnQualifier"},
|
||
+ { false, "2.5.4.6", "C", "C"},
|
||
+ { true, "2.5.4.5", "serialNumber", "SERIALNUMBER"},
|
||
+ { false, "2.5.4.7", "L", "L"},
|
||
+ { true, "2.5.4.12", "title", "T"},
|
||
+ { false, "2.5.4.4", "SN", "SN"},
|
||
+ { true, "2.5.4.42", "givenName", "G"},
|
||
+ { true, "2.5.4.43", "initials", "I"},
|
||
+ { true, "2.5.4.44", "generationQualifier", "OID.2.5.4.44"},
|
||
+ { false, "0.9.2342.19200300.100.1.25", "DC", "DC"},
|
||
+ { true, "0.9.2342.19200300.100.1.3", "MAIL", "OID,0.9.2342.19200300.100.1.3"},
|
||
+ { true, "0.9.2342.19200300.100.1.1", "UID", "OID.0.9.2342.19200300.100.1.1"},
|
||
+ { true, "2.5.4.13", "OID.2.5.4.13", "Description"},
|
||
+ { true, "2.5.4.16", "postalAddress", "OID.2.5.4.16"},
|
||
+ { true, "2.5.4.17", "postalCode", "PostalCode"},
|
||
+ { true, "2.5.4.18", "postOfficeBox", "POBox"},
|
||
+ { true, "2.5.4.51", "houseIdentifier", "OID.2.5.4.51"},
|
||
+ { false, "1.2.840.113549.1.9.1", "E", "E"},
|
||
+ { false, "2.5.4.9", "STREET", "STREET"},
|
||
+ { true, "2.5.4.65", "pseudonym", "OID.2.5.4.65"},
|
||
+ { true, "2.5.4.15", "businessCategory", "OID.2.5.4.15"},
|
||
+ { true, "2.5.4.41", "name", "OID.2.5.4.41"},
|
||
+
|
||
+ { false, NULL, NULL, NULL}
|
||
+};
|
||
+
|
||
+char *check_ad_attr_name(TALLOC_CTX *mem_ctx, const char *rdn)
|
||
+{
|
||
+ char *p;
|
||
+ size_t c;
|
||
+ size_t len;
|
||
+
|
||
+ if (rdn == NULL) {
|
||
+ return NULL;
|
||
+ }
|
||
+
|
||
+ p = strchr(rdn, '=');
|
||
+ if (p == NULL) {
|
||
+ return NULL;
|
||
+ }
|
||
+
|
||
+ len = p - rdn;
|
||
+ if (len == 0) {
|
||
+ return NULL;
|
||
+ }
|
||
+
|
||
+ for (c = 0; oid_attr_name_map[c].oid != NULL; c++) {
|
||
+ if (!oid_attr_name_map[c].nss_ad_differ) {
|
||
+ continue;
|
||
+ }
|
||
+
|
||
+ if (strlen(oid_attr_name_map[c].nss) != len
|
||
+ || strncmp(rdn, oid_attr_name_map[c].nss, len) != 0) {
|
||
+ continue;
|
||
+ }
|
||
+
|
||
+ return talloc_asprintf(mem_ctx, "%s%s", oid_attr_name_map[c].ad, p);
|
||
+ }
|
||
+
|
||
+ return NULL;
|
||
+}
|
||
diff --git a/src/lib/certmap/sss_certmap_int.h b/src/lib/certmap/sss_certmap_int.h
|
||
new file mode 100644
|
||
index 0000000000000000000000000000000000000000..28f1c596cfb5e78077b6a8e9baefa88b4900a022
|
||
--- /dev/null
|
||
+++ b/src/lib/certmap/sss_certmap_int.h
|
||
@@ -0,0 +1,187 @@
|
||
+/*
|
||
+ SSSD
|
||
+
|
||
+ Library for rule based certificate to user mapping
|
||
+
|
||
+ Authors:
|
||
+ Sumit Bose <sbose@redhat.com>
|
||
+
|
||
+ Copyright (C) 2017 Red Hat
|
||
+
|
||
+ This program is free software; you can redistribute it and/or modify
|
||
+ it under the terms of the GNU General Public License as published by
|
||
+ the Free Software Foundation; either version 3 of the License, or
|
||
+ (at your option) any later version.
|
||
+
|
||
+ This program is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
+ GNU General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU General Public License
|
||
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
+*/
|
||
+
|
||
+#include <sys/types.h>
|
||
+#include <regex.h>
|
||
+
|
||
+#ifndef __SSS_CERTMAP_INT_H__
|
||
+#define __SSS_CERTMAP_INT_H__
|
||
+
|
||
+#define CM_DEBUG(cm_ctx, format, ...) do { \
|
||
+ if (cm_ctx != NULL && cm_ctx->debug != NULL) { \
|
||
+ cm_ctx->debug(cm_ctx->debug_priv, __FILE__, __LINE__, __FUNCTION__, \
|
||
+ format, ##__VA_ARGS__); \
|
||
+ } \
|
||
+} while (0)
|
||
+
|
||
+#define DEFAULT_MATCH_RULE "<KU>digitalSignature<EKU>clientAuth"
|
||
+#define DEFAULT_MAP_RULE "LDAP:(userCertificate;binary={cert!bin})"
|
||
+
|
||
+enum san_opt {
|
||
+ SAN_OTHER_NAME = 0,
|
||
+ SAN_RFC822_NAME,
|
||
+ SAN_DNS_NAME,
|
||
+ SAN_X400_ADDRESS,
|
||
+ SAN_DIRECTORY_NAME,
|
||
+ SAN_EDIPART_NAME,
|
||
+ SAN_URI,
|
||
+ SAN_IP_ADDRESS,
|
||
+ SAN_REGISTERED_ID,
|
||
+ SAN_PKINIT,
|
||
+ SAN_NT,
|
||
+ SAN_PRINCIPAL,
|
||
+ SAN_STRING_OTHER_NAME,
|
||
+
|
||
+ SAN_END,
|
||
+ SAN_INVALID
|
||
+};
|
||
+
|
||
+/* KRB5 matching rule */
|
||
+enum relation_type {
|
||
+ relation_none = 0,
|
||
+ relation_and,
|
||
+ relation_or
|
||
+};
|
||
+
|
||
+struct component_list {
|
||
+ char *val;
|
||
+ regex_t regexp;
|
||
+ uint32_t ku;
|
||
+ const char **eku_oid_list;
|
||
+ enum san_opt san_opt;
|
||
+ char *str_other_name_oid;
|
||
+ uint8_t *bin_val;
|
||
+ size_t bin_val_len;
|
||
+ struct component_list *prev;
|
||
+ struct component_list *next;
|
||
+};
|
||
+
|
||
+struct krb5_match_rule {
|
||
+ enum relation_type r;
|
||
+ struct component_list *issuer;
|
||
+ struct component_list *subject;
|
||
+ struct component_list *ku;
|
||
+ struct component_list *eku;
|
||
+ struct component_list *san;
|
||
+};
|
||
+
|
||
+enum comp_type {
|
||
+ comp_none = 0,
|
||
+ comp_string,
|
||
+ comp_template
|
||
+};
|
||
+
|
||
+struct parsed_template {
|
||
+ char *name;
|
||
+ char *attr_name;
|
||
+ char *conversion;
|
||
+};
|
||
+
|
||
+struct ldap_mapping_rule_comp {
|
||
+ enum comp_type type;
|
||
+ char *val;
|
||
+ struct parsed_template *parsed_template;
|
||
+ struct ldap_mapping_rule_comp *prev;
|
||
+ struct ldap_mapping_rule_comp *next;
|
||
+};
|
||
+
|
||
+struct ldap_mapping_rule {
|
||
+ struct ldap_mapping_rule_comp *list;
|
||
+};
|
||
+
|
||
+struct match_map_rule {
|
||
+ uint32_t priority;
|
||
+ char *match_rule;
|
||
+ struct krb5_match_rule *parsed_match_rule;
|
||
+ char *map_rule;
|
||
+ struct ldap_mapping_rule *parsed_mapping_rule;
|
||
+ char **domains;
|
||
+ struct match_map_rule *prev;
|
||
+ struct match_map_rule *next;
|
||
+};
|
||
+
|
||
+struct priority_list {
|
||
+ uint32_t priority;
|
||
+ struct match_map_rule *rule_list;
|
||
+ struct priority_list *prev;
|
||
+ struct priority_list *next;
|
||
+};
|
||
+
|
||
+struct sss_certmap_ctx {
|
||
+ struct priority_list *prio_list;
|
||
+ sss_certmap_ext_debug *debug;
|
||
+ void *debug_priv;
|
||
+ struct ldap_mapping_rule *default_mapping_rule;
|
||
+};
|
||
+
|
||
+struct san_list {
|
||
+ enum san_opt san_opt;
|
||
+ char *val;
|
||
+ uint8_t *bin_val;
|
||
+ size_t bin_val_len;
|
||
+ char *other_name_oid;
|
||
+ char *short_name;
|
||
+ const char **rdn_list;
|
||
+ struct san_list *prev;
|
||
+ struct san_list *next;
|
||
+};
|
||
+
|
||
+/* key usage flags, see RFC 3280 section 4.2.1.3 */
|
||
+#define SSS_KU_DIGITAL_SIGNATURE 0x0080
|
||
+#define SSS_KU_NON_REPUDIATION 0x0040
|
||
+#define SSS_KU_KEY_ENCIPHERMENT 0x0020
|
||
+#define SSS_KU_DATA_ENCIPHERMENT 0x0010
|
||
+#define SSS_KU_KEY_AGREEMENT 0x0008
|
||
+#define SSS_KU_KEY_CERT_SIGN 0x0004
|
||
+#define SSS_KU_CRL_SIGN 0x0002
|
||
+#define SSS_KU_ENCIPHER_ONLY 0x0001
|
||
+#define SSS_KU_DECIPHER_ONLY 0x8000
|
||
+
|
||
+struct sss_cert_content {
|
||
+ const char *issuer_str;
|
||
+ const char **issuer_rdn_list;
|
||
+ const char *subject_str;
|
||
+ const char **subject_rdn_list;
|
||
+ uint32_t key_usage;
|
||
+ const char **extended_key_usage_oids;
|
||
+ struct san_list *san_list;
|
||
+
|
||
+ uint8_t *cert_der;
|
||
+ size_t cert_der_size;
|
||
+};
|
||
+
|
||
+int sss_cert_get_content(TALLOC_CTX *mem_ctx,
|
||
+ const uint8_t *der_blob, size_t der_size,
|
||
+ struct sss_cert_content **content);
|
||
+
|
||
+char *check_ad_attr_name(TALLOC_CTX *mem_ctx, const char *rdn);
|
||
+
|
||
+int parse_krb5_match_rule(struct sss_certmap_ctx *ctx,
|
||
+ const char *rule_start,
|
||
+ struct krb5_match_rule **match_rule);
|
||
+
|
||
+int parse_ldap_mapping_rule(struct sss_certmap_ctx *ctx,
|
||
+ const char *rule_start,
|
||
+ struct ldap_mapping_rule **mapping_rule);
|
||
+#endif /* __SSS_CERTMAP_INT_H__ */
|
||
diff --git a/src/lib/certmap/sss_certmap_krb5_match.c b/src/lib/certmap/sss_certmap_krb5_match.c
|
||
new file mode 100644
|
||
index 0000000000000000000000000000000000000000..e40f17b8ace46e61087e0a2fa570a362a84cead2
|
||
--- /dev/null
|
||
+++ b/src/lib/certmap/sss_certmap_krb5_match.c
|
||
@@ -0,0 +1,558 @@
|
||
+/*
|
||
+ SSSD
|
||
+
|
||
+ Library for rule based certificate to user mapping - KRB5 matching rules
|
||
+
|
||
+ Authors:
|
||
+ Sumit Bose <sbose@redhat.com>
|
||
+
|
||
+ Copyright (C) 2017 Red Hat
|
||
+
|
||
+ This program is free software; you can redistribute it and/or modify
|
||
+ it under the terms of the GNU General Public License as published by
|
||
+ the Free Software Foundation; either version 3 of the License, or
|
||
+ (at your option) any later version.
|
||
+
|
||
+ This program is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
+ GNU General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU General Public License
|
||
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
+*/
|
||
+
|
||
+#include "util/util.h"
|
||
+#include "util/cert.h"
|
||
+#include "util/crypto/sss_crypto.h"
|
||
+#include "lib/certmap/sss_certmap.h"
|
||
+#include "lib/certmap/sss_certmap_int.h"
|
||
+
|
||
+static bool is_dotted_decimal(const char *s, size_t len)
|
||
+{
|
||
+ size_t c = 0;
|
||
+ bool has_dot = false;
|
||
+
|
||
+ if (s == NULL || !isdigit(s[c++])) {
|
||
+ return false;
|
||
+ }
|
||
+
|
||
+ while ((len == 0 && s[c] != '\0') || (len != 0 && c < len)) {
|
||
+ if (s[c] != '.' && !isdigit(s[c])) {
|
||
+ return false;
|
||
+ }
|
||
+ if (!has_dot && s[c] == '.') {
|
||
+ has_dot = true;
|
||
+ }
|
||
+ c++;
|
||
+ }
|
||
+
|
||
+ return (has_dot && isdigit(s[c - 1]));
|
||
+}
|
||
+
|
||
+static int component_list_destructor(void *data)
|
||
+{
|
||
+ struct component_list *comp = talloc_get_type(data, struct component_list);
|
||
+
|
||
+ if (comp != NULL) {
|
||
+ regfree(&(comp->regexp));
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+/*
|
||
+ * The syntax of the MIT Kerberos style matching rules is:
|
||
+ * [KRB5:][relation-operator]component-rule ...
|
||
+ *
|
||
+ * where:
|
||
+ *
|
||
+ * relation-operator
|
||
+ * can be either &&, meaning all component rules must match, or ||,
|
||
+ * meaning only one component rule must match. The default is &&.
|
||
+ *
|
||
+ * component-rule
|
||
+ * can be one of the following. Note that there is no punctuation or whitespace between component rules.
|
||
+ * <SUBJECT>regular-expression
|
||
+ * <ISSUER>regular-expression
|
||
+ * <SAN>regular-expression
|
||
+ * <EKU>extended-key-usage
|
||
+ * <KU>key-usage
|
||
+ *
|
||
+ * see man sss-certmap for more details
|
||
+ *
|
||
+ */
|
||
+
|
||
+static int get_comp_value(TALLOC_CTX *mem_ctx,
|
||
+ struct sss_certmap_ctx *ctx,
|
||
+ const char **cur,
|
||
+ struct component_list **_comp)
|
||
+
|
||
+{
|
||
+ struct component_list *comp = NULL;
|
||
+ const char *end;
|
||
+ int ret;
|
||
+
|
||
+ comp = talloc_zero(mem_ctx, struct component_list);
|
||
+ if (comp == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ talloc_set_destructor((TALLOC_CTX *) comp, component_list_destructor);
|
||
+
|
||
+ end = strchr(*cur, '<');
|
||
+
|
||
+ if (end == NULL) {
|
||
+ comp->val = talloc_strdup(comp, *cur);
|
||
+ } else {
|
||
+ comp->val = talloc_strndup(comp, *cur, end - *cur);
|
||
+ }
|
||
+ if (comp->val == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+ if (*(comp->val) == '\0') {
|
||
+ CM_DEBUG(ctx, "Missing component value.");
|
||
+ ret = EINVAL;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ *cur += strlen(comp->val);
|
||
+ *_comp = comp;
|
||
+ ret = 0;
|
||
+
|
||
+done:
|
||
+ if (ret != 0) {
|
||
+ talloc_free(comp);
|
||
+ }
|
||
+
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+static int parse_krb5_get_eku_value(TALLOC_CTX *mem_ctx,
|
||
+ struct sss_certmap_ctx *ctx,
|
||
+ const char **cur,
|
||
+ struct component_list **_comp)
|
||
+{
|
||
+ struct component_list *comp = NULL;
|
||
+ int ret;
|
||
+ char **eku_list;
|
||
+ size_t c;
|
||
+ size_t k;
|
||
+ const char *o;
|
||
+ size_t e = 0;
|
||
+ int eku_list_size;
|
||
+
|
||
+ struct ext_key_usage {
|
||
+ const char *name;
|
||
+ const char *oid;
|
||
+ } ext_key_usage[] = {
|
||
+ /* RFC 3280 section 4.2.1.13 */
|
||
+ {"serverAuth", "1.3.6.1.5.5.7.3.1"},
|
||
+ {"clientAuth", "1.3.6.1.5.5.7.3.2"},
|
||
+ {"codeSigning", "1.3.6.1.5.5.7.3.3"},
|
||
+ {"emailProtection", "1.3.6.1.5.5.7.3.4"},
|
||
+ {"timeStamping", "1.3.6.1.5.5.7.3.8"},
|
||
+ {"OCSPSigning", "1.3.6.1.5.5.7.3.9"},
|
||
+
|
||
+ /* RFC 4556 section 3.2.2 */
|
||
+ {"KPClientAuth", "1.3.6.1.5.2.3.4"},
|
||
+ {"pkinit", "1.3.6.1.5.2.3.4"},
|
||
+
|
||
+ /* https://support.microsoft.com/en-us/help/287547/object-ids-associated-with-microsoft-cryptography*/
|
||
+ {"msScLogin", "1.3.6.1.4.1.311.20.2.2"},
|
||
+
|
||
+ {NULL ,0}
|
||
+ };
|
||
+
|
||
+ ret = get_comp_value(mem_ctx, ctx, cur, &comp);
|
||
+ if (ret != 0) {
|
||
+ CM_DEBUG(ctx, "Failed to parse regexp.");
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ ret = split_on_separator(mem_ctx, comp->val, ',', true, true,
|
||
+ &eku_list, &eku_list_size);
|
||
+ if (ret != 0) {
|
||
+ CM_DEBUG(ctx, "Failed to split list.");
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ for (c = 0; eku_list[c] != NULL; c++) {
|
||
+ for (k = 0; ext_key_usage[k].name != NULL; k++) {
|
||
+CM_DEBUG(ctx, "[%s][%s].", eku_list[c], ext_key_usage[k].name);
|
||
+ if (strcasecmp(eku_list[c], ext_key_usage[k].name) == 0) {
|
||
+ if (comp->eku_oid_list == NULL) {
|
||
+ comp->eku_oid_list = talloc_zero_array(comp, const char *,
|
||
+ eku_list_size + 1);
|
||
+ if (comp->eku_oid_list == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ comp->eku_oid_list[e] = talloc_strdup(comp->eku_oid_list,
|
||
+ ext_key_usage[k].oid);
|
||
+ if (comp->eku_oid_list[e] == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+ e++;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (ext_key_usage[k].name == NULL) {
|
||
+ /* check for an dotted-decimal OID */
|
||
+ if (*(eku_list[c]) != '.') {
|
||
+ o = eku_list[c];
|
||
+ if (is_dotted_decimal(o, 0)) {
|
||
+ /* looks like a OID, only '.' and digits */
|
||
+ comp->eku_oid_list[e] = talloc_strdup(comp->eku_oid_list,
|
||
+ eku_list[c]);
|
||
+ if (comp->eku_oid_list[e] == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+ e++;
|
||
+ continue;
|
||
+ }
|
||
+ }
|
||
+ CM_DEBUG(ctx, "No matching extended key usage found.");
|
||
+ ret = EINVAL;
|
||
+ goto done;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ ret = 0;
|
||
+
|
||
+done:
|
||
+ if (ret == 0) {
|
||
+ *_comp = comp;
|
||
+ } else {
|
||
+ talloc_free(comp);
|
||
+ }
|
||
+
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+static int parse_krb5_get_ku_value(TALLOC_CTX *mem_ctx,
|
||
+ struct sss_certmap_ctx *ctx,
|
||
+ const char **cur,
|
||
+ struct component_list **_comp)
|
||
+{
|
||
+ struct component_list *comp = NULL;
|
||
+ int ret;
|
||
+ char **ku_list;
|
||
+ size_t c;
|
||
+ size_t k;
|
||
+
|
||
+ struct key_usage {
|
||
+ const char *name;
|
||
+ uint32_t flag;
|
||
+ } key_usage[] = {
|
||
+ {"digitalSignature" , SSS_KU_DIGITAL_SIGNATURE},
|
||
+ {"nonRepudiation" , SSS_KU_NON_REPUDIATION},
|
||
+ {"keyEncipherment" , SSS_KU_KEY_ENCIPHERMENT},
|
||
+ {"dataEncipherment" , SSS_KU_DATA_ENCIPHERMENT},
|
||
+ {"keyAgreement" , SSS_KU_KEY_AGREEMENT},
|
||
+ {"keyCertSign" , SSS_KU_KEY_CERT_SIGN},
|
||
+ {"cRLSign" , SSS_KU_CRL_SIGN},
|
||
+ {"encipherOnly" , SSS_KU_ENCIPHER_ONLY},
|
||
+ {"decipherOnly" , SSS_KU_DECIPHER_ONLY},
|
||
+ {NULL ,0}
|
||
+ };
|
||
+
|
||
+
|
||
+ ret = get_comp_value(mem_ctx, ctx, cur, &comp);
|
||
+ if (ret != 0) {
|
||
+ CM_DEBUG(ctx, "Failed to get value.");
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ ret = split_on_separator(mem_ctx, comp->val, ',', true, true,
|
||
+ &ku_list, NULL);
|
||
+ if (ret != 0) {
|
||
+ CM_DEBUG(ctx, "Failed to split list.");
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ for (c = 0; ku_list[c] != NULL; c++) {
|
||
+ for (k = 0; key_usage[k].name != NULL; k++) {
|
||
+ if (strcasecmp(ku_list[c], key_usage[k].name) == 0) {
|
||
+ comp->ku |= key_usage[k].flag;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (key_usage[k].name == NULL) {
|
||
+ /* FIXME: add check for numerical ku */
|
||
+ CM_DEBUG(ctx, "No matching key usage found.");
|
||
+ ret = EINVAL;
|
||
+ goto done;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ ret = 0;
|
||
+
|
||
+done:
|
||
+ if (ret == 0) {
|
||
+ *_comp = comp;
|
||
+ } else {
|
||
+ talloc_free(comp);
|
||
+ }
|
||
+
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+static int parse_krb5_get_component_value(TALLOC_CTX *mem_ctx,
|
||
+ struct sss_certmap_ctx *ctx,
|
||
+ const char **cur,
|
||
+ struct component_list **_comp)
|
||
+{
|
||
+ struct component_list *comp = NULL;
|
||
+ int ret;
|
||
+
|
||
+ ret = get_comp_value(mem_ctx, ctx, cur, &comp);
|
||
+ if (ret != 0) {
|
||
+ CM_DEBUG(ctx, "Failed to parse regexp.");
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ ret = regcomp(&(comp->regexp), comp->val, REG_EXTENDED);
|
||
+ if (ret != 0) {
|
||
+ CM_DEBUG(ctx, "Failed to parse regexp.");
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ ret = 0;
|
||
+
|
||
+done:
|
||
+ if (ret == 0) {
|
||
+ *_comp = comp;
|
||
+ } else {
|
||
+ talloc_free(comp);
|
||
+ }
|
||
+
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+struct san_name {
|
||
+ const char *name;
|
||
+ enum san_opt san_opt;
|
||
+ bool is_string;
|
||
+} san_names[] = {
|
||
+ /* https://www.ietf.org/rfc/rfc3280.txt section 4.2.1.7 */
|
||
+ {"otherName", SAN_OTHER_NAME, false},
|
||
+ {"rfc822Name", SAN_RFC822_NAME,true},
|
||
+ {"dNSName", SAN_DNS_NAME, true},
|
||
+ {"x400Address", SAN_X400_ADDRESS, false},
|
||
+ {"directoryName", SAN_DIRECTORY_NAME, true},
|
||
+ {"ediPartyName", SAN_EDIPART_NAME, false},
|
||
+ {"uniformResourceIdentifier", SAN_URI, true},
|
||
+ {"iPAddress", SAN_IP_ADDRESS, true},
|
||
+ {"registeredID", SAN_REGISTERED_ID, true},
|
||
+ /* https://www.ietf.org/rfc/rfc4556.txt section 3.2.2 */
|
||
+ {"pkinitSAN", SAN_PKINIT, true},
|
||
+ /* https://support.microsoft.com/en-us/help/287547/object-ids-associated-with-microsoft-cryptography */
|
||
+ {"ntPrincipalName", SAN_NT, true},
|
||
+ /* both previous principal types */
|
||
+ {"Principal", SAN_PRINCIPAL, true},
|
||
+ {"stringOtherName", SAN_STRING_OTHER_NAME, true},
|
||
+ {NULL, SAN_END, false}
|
||
+};
|
||
+
|
||
+static int parse_krb5_get_san_option(TALLOC_CTX *mem_ctx,
|
||
+ struct sss_certmap_ctx *ctx,
|
||
+ const char **cur,
|
||
+ enum san_opt *option,
|
||
+ char **str_other_name_oid)
|
||
+{
|
||
+ char *end;
|
||
+ size_t c;
|
||
+ size_t len;
|
||
+
|
||
+ end = strchr(*cur, '>');
|
||
+ if (end == NULL) {
|
||
+ CM_DEBUG(ctx, "Failed to parse SAN option.");
|
||
+ return EINVAL;
|
||
+ }
|
||
+
|
||
+ len = end - *cur;
|
||
+
|
||
+ if (len == 0) {
|
||
+ c= SAN_PRINCIPAL;
|
||
+ } else {
|
||
+ for (c = 0; san_names[c].name != NULL; c++) {
|
||
+ if (strncasecmp(*cur, san_names[c].name, len) == 0) {
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ if (san_names[c].name == NULL) {
|
||
+ if (is_dotted_decimal(*cur, len)) {
|
||
+ c = SAN_STRING_OTHER_NAME;
|
||
+ *str_other_name_oid = talloc_strndup(mem_ctx, *cur, len);
|
||
+ if (*str_other_name_oid == NULL) {
|
||
+ CM_DEBUG(ctx, "talloc_strndup failed.");
|
||
+ return ENOMEM;
|
||
+ }
|
||
+ } else {
|
||
+ CM_DEBUG(ctx, "Unknown SAN option.");
|
||
+ return EINVAL;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ *option = san_names[c].san_opt;
|
||
+ *cur = end + 1;
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static int parse_krb5_get_san_value(TALLOC_CTX *mem_ctx,
|
||
+ struct sss_certmap_ctx *ctx,
|
||
+ const char **cur,
|
||
+ struct component_list **_comp)
|
||
+{
|
||
+ struct component_list *comp = NULL;
|
||
+ enum san_opt san_opt = SAN_PRINCIPAL;
|
||
+ int ret;
|
||
+ char *str_other_name_oid = NULL;
|
||
+
|
||
+ if (*(*cur - 1) == ':') {
|
||
+ ret = parse_krb5_get_san_option(mem_ctx, ctx, cur, &san_opt,
|
||
+ &str_other_name_oid);
|
||
+ if (ret != 0) {
|
||
+ goto done;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (san_names[san_opt].is_string) {
|
||
+ ret = parse_krb5_get_component_value(mem_ctx, ctx, cur, &comp);
|
||
+ if (ret != 0) {
|
||
+ goto done;
|
||
+ }
|
||
+ } else {
|
||
+ ret = get_comp_value(mem_ctx, ctx, cur, &comp);
|
||
+ if (ret != 0) {
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ if (comp->val != NULL) {
|
||
+ comp->bin_val = sss_base64_decode(comp, comp->val,
|
||
+ &comp->bin_val_len);
|
||
+ /* for some reasons the NSS version of sss_base64_decode might
|
||
+ * return a non-NULL value on error but len is still 0, so better
|
||
+ * check both. */
|
||
+ if (comp->bin_val == NULL || comp->bin_val_len == 0) {
|
||
+ CM_DEBUG(ctx, "Base64 decode failed.");
|
||
+ ret = EINVAL;
|
||
+ goto done;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ comp->san_opt = san_opt;
|
||
+
|
||
+done:
|
||
+ if (ret == 0) {
|
||
+ comp->str_other_name_oid = talloc_steal(comp, str_other_name_oid);
|
||
+ *_comp = comp;
|
||
+ } else {
|
||
+ talloc_free(comp);
|
||
+ talloc_free(str_other_name_oid);
|
||
+ }
|
||
+
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+int parse_krb5_match_rule(struct sss_certmap_ctx *ctx,
|
||
+ const char *rule_start,
|
||
+ struct krb5_match_rule **match_rule)
|
||
+{
|
||
+ const char *cur;
|
||
+ struct krb5_match_rule *rule;
|
||
+ struct component_list *comp;
|
||
+ int ret;
|
||
+
|
||
+ rule = talloc_zero(ctx, struct krb5_match_rule);
|
||
+ if (rule == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ cur = rule_start;
|
||
+ /* check relation */
|
||
+ if (strncmp(cur, "&&", 2) == 0) {
|
||
+ rule->r = relation_and;
|
||
+ cur += 2;
|
||
+ } else if (strncmp(cur, "||", 2) == 0) {
|
||
+ rule->r = relation_or;
|
||
+ cur += 2;
|
||
+ } else {
|
||
+ rule->r = relation_and;
|
||
+ }
|
||
+
|
||
+ while (*cur != '\0') {
|
||
+ /* new component must start with '<' */
|
||
+ if (*cur != '<') {
|
||
+ CM_DEBUG(ctx, "Invalid KRB5 matching rule.");
|
||
+ ret = EINVAL;
|
||
+ goto done;
|
||
+ }
|
||
+ cur++;
|
||
+
|
||
+ if (strncmp(cur, "ISSUER>", 7) == 0) {
|
||
+ cur += 7;
|
||
+ ret = parse_krb5_get_component_value(rule, ctx, &cur, &comp);
|
||
+ if (ret != 0) {
|
||
+ goto done;
|
||
+ }
|
||
+ DLIST_ADD(rule->issuer, comp);
|
||
+ } else if (strncmp(cur, "SUBJECT>", 8) == 0) {
|
||
+ cur += 8;
|
||
+ ret = parse_krb5_get_component_value(rule, ctx, &cur, &comp);
|
||
+ if (ret != 0) {
|
||
+ goto done;
|
||
+ }
|
||
+ DLIST_ADD(rule->subject, comp);
|
||
+ } else if (strncmp(cur, "KU>", 3) == 0) {
|
||
+ cur += 3;
|
||
+ ret = parse_krb5_get_ku_value(rule, ctx, &cur, &comp);
|
||
+ if (ret != 0) {
|
||
+ goto done;
|
||
+ }
|
||
+ DLIST_ADD(rule->ku, comp);
|
||
+ } else if (strncmp(cur, "EKU>", 4) == 0) {
|
||
+ cur += 4;
|
||
+ ret = parse_krb5_get_eku_value(rule, ctx, &cur, &comp);
|
||
+ if (ret != 0) {
|
||
+ goto done;
|
||
+ }
|
||
+ DLIST_ADD(rule->eku, comp);
|
||
+ } else if (strncmp(cur, "SAN>", 4) == 0
|
||
+ || strncmp(cur, "SAN:", 4) == 0) {
|
||
+ cur += 4;
|
||
+ ret = parse_krb5_get_san_value(rule, ctx, &cur, &comp);
|
||
+ if (ret != 0) {
|
||
+ goto done;
|
||
+ }
|
||
+ DLIST_ADD(rule->san, comp);
|
||
+ } else {
|
||
+ CM_DEBUG(ctx, "Invalid KRB5 matching rule.");
|
||
+ ret = EINVAL;
|
||
+ goto done;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ ret = 0;
|
||
+
|
||
+done:
|
||
+ if (ret == 0) {
|
||
+ *match_rule = rule;
|
||
+ } else {
|
||
+ talloc_free(rule);
|
||
+ }
|
||
+
|
||
+ return ret;
|
||
+}
|
||
diff --git a/src/lib/certmap/sss_certmap_ldap_mapping.c b/src/lib/certmap/sss_certmap_ldap_mapping.c
|
||
new file mode 100644
|
||
index 0000000000000000000000000000000000000000..c64c05b311f043b4d70f98f718780601c3e6a002
|
||
--- /dev/null
|
||
+++ b/src/lib/certmap/sss_certmap_ldap_mapping.c
|
||
@@ -0,0 +1,367 @@
|
||
+/*
|
||
+ SSSD
|
||
+
|
||
+ Library for rule based certificate to user mapping - LDAP mapping rules
|
||
+
|
||
+ Authors:
|
||
+ Sumit Bose <sbose@redhat.com>
|
||
+
|
||
+ Copyright (C) 2017 Red Hat
|
||
+
|
||
+ This program is free software; you can redistribute it and/or modify
|
||
+ it under the terms of the GNU General Public License as published by
|
||
+ the Free Software Foundation; either version 3 of the License, or
|
||
+ (at your option) any later version.
|
||
+
|
||
+ This program is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
+ GNU General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU General Public License
|
||
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
+*/
|
||
+
|
||
+#include "util/util.h"
|
||
+#include "util/cert.h"
|
||
+#include "util/crypto/sss_crypto.h"
|
||
+#include "lib/certmap/sss_certmap.h"
|
||
+#include "lib/certmap/sss_certmap_int.h"
|
||
+struct template_table {
|
||
+ const char *name;
|
||
+ const char **attr_name;
|
||
+ const char **conversion;
|
||
+};
|
||
+
|
||
+const char *empty[] = {NULL};
|
||
+const char *name_attr[] = {"short_name", NULL};
|
||
+const char *x500_conv[] = {"ad_x500", "ad", "ad_ldap",
|
||
+ "nss_x500", "nss", "nss_ldap", NULL};
|
||
+const char *bin_conv[] = {"bin", "base64", NULL};
|
||
+
|
||
+struct template_table template_table[] = {
|
||
+ {"issuer_dn", empty, x500_conv},
|
||
+ {"subject_dn", empty, x500_conv},
|
||
+ {"cert", empty, bin_conv},
|
||
+ {"subject_rfc822_name", name_attr, empty},
|
||
+ {"subject_dns_name", name_attr, empty},
|
||
+ {"subject_x400_address", empty, empty},
|
||
+ {"subject_directory_name", empty, empty},
|
||
+ {"subject_ediparty_name", empty, empty},
|
||
+ {"subject_uri", empty, empty},
|
||
+ {"subject_ip_address", empty, empty},
|
||
+ {"subject_registered_id", empty, empty},
|
||
+ {"subject_pkinit_principal", name_attr, empty},
|
||
+ {"subject_nt_principal", name_attr, empty},
|
||
+ {"subject_principal", name_attr, empty},
|
||
+ {NULL, NULL, NULL}};
|
||
+
|
||
+static int check_parsed_template(struct sss_certmap_ctx *ctx,
|
||
+ struct parsed_template *parsed)
|
||
+{
|
||
+ size_t n;
|
||
+ size_t a;
|
||
+ size_t c;
|
||
+ bool attr_name_valid = false;
|
||
+ bool conversion_valid = false;
|
||
+
|
||
+ for (n = 0; template_table[n].name != NULL; n++) {
|
||
+ if (strcmp(template_table[n].name, parsed->name) != 0) {
|
||
+ continue;
|
||
+ }
|
||
+
|
||
+ if (parsed->attr_name != NULL) {
|
||
+ for (a = 0; template_table[n].attr_name[a] != NULL; a++) {
|
||
+ if (strcmp(template_table[n].attr_name[a],
|
||
+ parsed->attr_name) == 0) {
|
||
+ attr_name_valid = true;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ } else {
|
||
+ attr_name_valid = true;
|
||
+ }
|
||
+
|
||
+ if (parsed->conversion != NULL) {
|
||
+ for (c = 0; template_table[n].conversion[c] != NULL; c++) {
|
||
+ if (strcmp(template_table[n].conversion[c],
|
||
+ parsed->conversion) == 0) {
|
||
+ conversion_valid = true;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ } else {
|
||
+ conversion_valid = true;
|
||
+ }
|
||
+
|
||
+ if (attr_name_valid && conversion_valid) {
|
||
+ return 0;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return EINVAL;
|
||
+}
|
||
+
|
||
+static int parse_template(TALLOC_CTX *mem_ctx, struct sss_certmap_ctx *ctx,
|
||
+ const char *template,
|
||
+ struct parsed_template **parsed_template)
|
||
+{
|
||
+ int ret;
|
||
+ struct parsed_template *parsed = NULL;
|
||
+ const char *dot;
|
||
+ const char *excl;
|
||
+ const char *p;
|
||
+
|
||
+ parsed = talloc_zero(mem_ctx, struct parsed_template);
|
||
+ if (parsed == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ dot = strchr(template, '.');
|
||
+ if (dot != NULL) {
|
||
+ p = strchr(dot + 1, '.');
|
||
+ if (p != NULL) {
|
||
+ CM_DEBUG(ctx, "Only one '.' allowed in template.");
|
||
+ ret = EINVAL;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ if (dot == template) {
|
||
+ CM_DEBUG(ctx, "Missing name in template.");
|
||
+ ret = EINVAL;
|
||
+ goto done;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ excl = strchr(template, '!');
|
||
+ if (excl != NULL) {
|
||
+ p = strchr(excl + 1, '!');
|
||
+ if (p != NULL) {
|
||
+ CM_DEBUG(ctx, "Only one '!' allowed in template.");
|
||
+ ret = EINVAL;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ if (excl == template) {
|
||
+ CM_DEBUG(ctx, "Missing name in template.");
|
||
+ ret = EINVAL;
|
||
+ goto done;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (excl != NULL && excl[1] != '\0') {
|
||
+ parsed->conversion = talloc_strdup(parsed, excl + 1);
|
||
+ if (parsed->conversion == NULL) {
|
||
+ CM_DEBUG(ctx, "Memory allocation failed.");
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (dot != NULL && dot[1] != '\0' && dot[1] != '!') {
|
||
+ if (excl == NULL) {
|
||
+ parsed->attr_name = talloc_strdup(parsed, dot + 1);
|
||
+ } else {
|
||
+ parsed->attr_name = talloc_strndup(parsed, dot + 1,
|
||
+ (excl - dot - 1));
|
||
+ }
|
||
+ if (parsed->attr_name == NULL) {
|
||
+ CM_DEBUG(ctx, "Memory allocation failed.");
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (dot != NULL) {
|
||
+ parsed->name = talloc_strndup(parsed, template, (dot - template));
|
||
+ } else if (excl != NULL) {
|
||
+ parsed->name = talloc_strndup(parsed, template, (excl - template));
|
||
+ } else {
|
||
+ parsed->name = talloc_strdup(parsed, template);
|
||
+ }
|
||
+ if (parsed->name == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ ret = check_parsed_template(ctx, parsed);
|
||
+ if (ret != 0) {
|
||
+ CM_DEBUG(ctx, "Parse template invalid.");
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ ret = 0;
|
||
+
|
||
+done:
|
||
+ if (ret == 0) {
|
||
+ *parsed_template = parsed;
|
||
+ } else {
|
||
+ talloc_free(parsed);
|
||
+ }
|
||
+
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+static int add_comp(struct sss_certmap_ctx *ctx, struct ldap_mapping_rule *rule,
|
||
+ const char *string, enum comp_type type)
|
||
+{
|
||
+ int ret;
|
||
+ struct ldap_mapping_rule_comp *comp;
|
||
+
|
||
+ comp = talloc_zero(rule, struct ldap_mapping_rule_comp);
|
||
+ if (comp == NULL) {
|
||
+ return ENOMEM;
|
||
+ }
|
||
+
|
||
+ comp->type = type;
|
||
+ comp->val = talloc_strdup(comp, string);
|
||
+ if (comp->val == NULL) {
|
||
+ talloc_free(comp);
|
||
+ return ENOMEM;
|
||
+ }
|
||
+
|
||
+ if (type == comp_template) {
|
||
+ ret = parse_template(comp, ctx, string, &comp->parsed_template);
|
||
+ if (ret != 0) {
|
||
+ talloc_free(comp);
|
||
+ return ret;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ DLIST_ADD_END(rule->list, comp, struct ldap_mapping_rule_comp *);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static int add_string(struct sss_certmap_ctx *ctx,
|
||
+ struct ldap_mapping_rule *rule, const char *string)
|
||
+{
|
||
+ return add_comp(ctx, rule, string, comp_string);
|
||
+}
|
||
+
|
||
+static int add_template(struct sss_certmap_ctx *ctx,
|
||
+ struct ldap_mapping_rule *rule, const char *string)
|
||
+{
|
||
+ return add_comp(ctx, rule, string, comp_template);
|
||
+}
|
||
+
|
||
+int parse_ldap_mapping_rule(struct sss_certmap_ctx *ctx,
|
||
+ const char *rule_start,
|
||
+ struct ldap_mapping_rule **mapping_rule)
|
||
+{
|
||
+ size_t c;
|
||
+ const char *cur;
|
||
+ char *tmp_string = NULL;
|
||
+ size_t tmp_string_size;
|
||
+ struct ldap_mapping_rule *rule = NULL;
|
||
+ int ret;
|
||
+ bool in_template = false;
|
||
+
|
||
+ rule = talloc_zero(ctx, struct ldap_mapping_rule);
|
||
+ if (rule == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ tmp_string_size = strlen(rule_start) + 1;
|
||
+ tmp_string = talloc_zero_size(ctx, tmp_string_size);
|
||
+ if (tmp_string == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ cur = rule_start;
|
||
+ c = 0;
|
||
+
|
||
+ while (*cur != '\0') {
|
||
+ if (c > tmp_string_size) {
|
||
+ CM_DEBUG(ctx, "Cannot parse mapping rule.");
|
||
+ ret = EIO;
|
||
+ goto done;
|
||
+ }
|
||
+ switch (*cur) {
|
||
+ case '{':
|
||
+ if (in_template) {
|
||
+ CM_DEBUG(ctx, "'{' not allowed in templates.");
|
||
+ ret = EINVAL;
|
||
+ goto done;
|
||
+ }
|
||
+ if (cur[1] == '{') {
|
||
+ /* Add only a single '{' to the output */
|
||
+ tmp_string[c] = '{';
|
||
+ c++;
|
||
+ cur += 2;
|
||
+ } else {
|
||
+ if (c != 0) {
|
||
+ ret = add_string(ctx, rule, tmp_string);
|
||
+ if (ret != 0) {
|
||
+ CM_DEBUG(ctx, "Failed to add string.");
|
||
+ ret = EINVAL;
|
||
+ goto done;
|
||
+ }
|
||
+ memset(tmp_string, 0, tmp_string_size);
|
||
+ c = 0;
|
||
+ }
|
||
+ cur++;
|
||
+ in_template = true;
|
||
+ }
|
||
+ break;
|
||
+ case '}':
|
||
+ if (cur[1] == '}') {
|
||
+ if (in_template) {
|
||
+ CM_DEBUG(ctx, "'}}' not allowed in templates.");
|
||
+ ret = EINVAL;
|
||
+ goto done;
|
||
+ } else {
|
||
+ /* Add only a single '}' to the output */
|
||
+ tmp_string[c] = '}';
|
||
+ c++;
|
||
+ cur += 2;
|
||
+ }
|
||
+ } else {
|
||
+ ret = add_template(ctx, rule, tmp_string);
|
||
+ if (ret != 0) {
|
||
+ CM_DEBUG(ctx, "Failed to add template.");
|
||
+ ret = EINVAL;
|
||
+ goto done;
|
||
+ }
|
||
+ memset(tmp_string, 0, tmp_string_size);
|
||
+ c = 0;
|
||
+ cur++;
|
||
+ in_template = false;
|
||
+ }
|
||
+ break;
|
||
+ default:
|
||
+ tmp_string[c] = *cur;
|
||
+ c++;
|
||
+ cur++;
|
||
+ }
|
||
+ }
|
||
+ if (in_template) {
|
||
+ CM_DEBUG(ctx, "Rule ended inside template.");
|
||
+ ret = EINVAL;
|
||
+ goto done;
|
||
+ }
|
||
+ if (c != 0) {
|
||
+ ret = add_string(ctx, rule, tmp_string);
|
||
+ if (ret != 0) {
|
||
+ CM_DEBUG(ctx, "Failed to add string.");
|
||
+ ret = EINVAL;
|
||
+ goto done;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ ret = 0;
|
||
+
|
||
+done:
|
||
+ if (ret == 0) {
|
||
+ *mapping_rule = rule;
|
||
+ } else {
|
||
+ talloc_free(rule);
|
||
+ }
|
||
+
|
||
+ talloc_free(tmp_string);
|
||
+
|
||
+ return ret;
|
||
+}
|
||
diff --git a/src/man/Makefile.am b/src/man/Makefile.am
|
||
index 215ce693b56e74db394dbc238c03c87f5f6efe99..142d6e2743f814294e3d92c8342070b8230bb3e5 100644
|
||
--- a/src/man/Makefile.am
|
||
+++ b/src/man/Makefile.am
|
||
@@ -59,7 +59,7 @@ man_MANS = \
|
||
sss_useradd.8 sss_userdel.8 sss_usermod.8 \
|
||
sss_groupadd.8 sss_groupdel.8 sss_groupmod.8 \
|
||
sssd.8 sssd.conf.5 sssd-ldap.5 \
|
||
- sssd-krb5.5 sssd-simple.5 \
|
||
+ sssd-krb5.5 sssd-simple.5 sss-certmap.5 \
|
||
sssd_krb5_locator_plugin.8 sss_groupshow.8 \
|
||
pam_sss.8 sss_obfuscate.8 sss_cache.8 sss_debuglevel.8 sss_seed.8 \
|
||
sss_override.8 idmap_sss.8 sssctl.8 \
|
||
diff --git a/src/man/po/po4a.cfg b/src/man/po/po4a.cfg
|
||
index ffcf9a2793da3c0115bc846744ccb9592a9a68ef..d1f6ac39f841c61ae3d2393fb3402dc21b9cbd69 100644
|
||
--- a/src/man/po/po4a.cfg
|
||
+++ b/src/man/po/po4a.cfg
|
||
@@ -6,6 +6,7 @@
|
||
[type:docbook] pam_sss.8.xml $lang:$(builddir)/$lang/pam_sss.8.xml
|
||
[type:docbook] sssd_krb5_locator_plugin.8.xml $lang:$(builddir)/$lang/sssd_krb5_locator_plugin.8.xml
|
||
[type:docbook] sssd-simple.5.xml $lang:$(builddir)/$lang/sssd-simple.5.xml
|
||
+[type:docbook] sss-certmap.5.xml $lang:$(builddir)/$lang/sss-certmap.5.xml
|
||
[type:docbook] sssd-ipa.5.xml $lang:$(builddir)/$lang/sssd-ipa.5.xml
|
||
[type:docbook] sssd-ad.5.xml $lang:$(builddir)/$lang/sssd-ad.5.xml
|
||
[type:docbook] sssd-sudo.5.xml $lang:$(builddir)/$lang/sssd-sudo.5.xml
|
||
diff --git a/src/man/sss-certmap.5.xml b/src/man/sss-certmap.5.xml
|
||
new file mode 100644
|
||
index 0000000000000000000000000000000000000000..bbe68509f2222613a7ed69599519d7fca0506df0
|
||
--- /dev/null
|
||
+++ b/src/man/sss-certmap.5.xml
|
||
@@ -0,0 +1,600 @@
|
||
+<?xml version="1.0" encoding="UTF-8"?>
|
||
+<!DOCTYPE reference PUBLIC "-//OASIS//DTD DocBook V4.4//EN"
|
||
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
|
||
+<reference>
|
||
+<title>SSSD Manual pages</title>
|
||
+<refentry>
|
||
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/upstream.xml" />
|
||
+
|
||
+ <refmeta>
|
||
+ <refentrytitle>sss-certmap</refentrytitle>
|
||
+ <manvolnum>5</manvolnum>
|
||
+ <refmiscinfo class="manual">File Formats and Conventions</refmiscinfo>
|
||
+ </refmeta>
|
||
+
|
||
+ <refnamediv id='name'>
|
||
+ <refname>sss-certmap</refname>
|
||
+ <refpurpose>SSSD Certificate Matching and Mapping Rules</refpurpose>
|
||
+ </refnamediv>
|
||
+
|
||
+ <refsect1 id='description'>
|
||
+ <title>DESCRIPTION</title>
|
||
+ <para>
|
||
+ The manual page describes the rules which can be used by SSSD and
|
||
+ other components to match X.509 certificates and map them to
|
||
+ accounts.
|
||
+ </para>
|
||
+ <para>
|
||
+ Each rule has four components, a <quote>priority</quote>, a
|
||
+ <quote>matching rule</quote>, a <quote>mapping rule</quote> and a
|
||
+ <quote>domain list</quote>. All components are optional. A missing
|
||
+ <quote>priority</quote> will add the rule with the lowest priority.
|
||
+ The default <quote>matching rule</quote> will match certificates with
|
||
+ the digitalSignature key usage and clientAuth extended key usage. If
|
||
+ the <quote>mapping rule</quote> is empty the certificates will be
|
||
+ searched in the userCertificate attribute as DER encoded binary. If
|
||
+ no domains are given only the local domain will be searched.
|
||
+ </para>
|
||
+ </refsect1>
|
||
+
|
||
+ <refsect1 id='components'>
|
||
+ <title>RULE COMPONENTS</title>
|
||
+ <refsect2 id='priority'>
|
||
+ <title>PRIORITY</title>
|
||
+ <para>
|
||
+ The rules are process by priority while the number '0' (zero)
|
||
+ indicates the highest priority. The higher the number the lower is
|
||
+ the priority. A missing value indicates the lowest priority.
|
||
+ </para>
|
||
+ <para>
|
||
+ Internally the priority is treated as unsigned 32bit integer, using
|
||
+ a priority value larger than 4294967295 will cause an error.
|
||
+ </para>
|
||
+ </refsect2>
|
||
+ <refsect2 id='match'>
|
||
+ <title>MATCHING RULE</title>
|
||
+ <para>
|
||
+ The matching rule is used to select a certificate to which the
|
||
+ mapping rule should be applied. It uses a system similar to the one
|
||
+ used by <quote>pkinit_cert_match</quote> option of MIT Kerberos. It
|
||
+ consists of a keyword enclosed by '<' and '>' which identified
|
||
+ a certain part of the certificate and a pattern which should be
|
||
+ found for the rule to match. Multiple keyword pattern pairs can be
|
||
+ either joined with '&&' (and) or '||' (or).
|
||
+ </para>
|
||
+ <para>
|
||
+ The available options are:
|
||
+ <variablelist>
|
||
+ <varlistentry>
|
||
+ <term><SUBJECT>regular-expression</term>
|
||
+ <listitem>
|
||
+ <para>
|
||
+ With this a part or the whole subject name of the
|
||
+ certificate can be matched. For the matching POSIX
|
||
+ Extended Regular Expression syntax is used, see regex(7)
|
||
+ for details.
|
||
+ </para>
|
||
+ <para>
|
||
+ For the matching the subject name stored in the
|
||
+ certificate in DER encoded ASN.1 is converted into a
|
||
+ string according to RFC 4514. This means the most
|
||
+ specific name component comes first. Please note that
|
||
+ not all possible attribute names are covered by RFC
|
||
+ 4514. The names included are 'CN', 'L', 'ST', 'O',
|
||
+ 'OU', 'C', 'STREET', 'DC' and 'UID'. Other attribute
|
||
+ names might be shown differently on different platform
|
||
+ and by different tools. To avoid confusion those
|
||
+ attribute names are best not used or covered by a
|
||
+ suitable regular-expression.
|
||
+ </para>
|
||
+ <para>
|
||
+ Example: <SUBJECT>.*,DC=MY,DC=DOMAIN
|
||
+ </para>
|
||
+ </listitem>
|
||
+ </varlistentry>
|
||
+ <varlistentry>
|
||
+ <term><ISSUER>regular-expression</term>
|
||
+ <listitem>
|
||
+ <para>
|
||
+ With this a part or the whole issuer name of the
|
||
+ certificate can be matched. All comments for
|
||
+ <SUBJECT> apply her as well.
|
||
+ </para>
|
||
+ <para>
|
||
+ Example: <ISSUER>^CN=My-CA,DC=MY,DC=DOMAIN$
|
||
+ </para>
|
||
+ </listitem>
|
||
+ </varlistentry>
|
||
+ <varlistentry>
|
||
+ <term><KU>key-usage</term>
|
||
+ <listitem>
|
||
+ <para>
|
||
+ This option can be used to specify which key usage
|
||
+ values the certificate should have. The following value
|
||
+ can be used in a comma separate list:
|
||
+ <itemizedlist>
|
||
+ <listitem><para>digitalSignature</para></listitem>
|
||
+ <listitem><para>nonRepudiation</para></listitem>
|
||
+ <listitem><para>keyEncipherment</para></listitem>
|
||
+ <listitem><para>dataEncipherment</para></listitem>
|
||
+ <listitem><para>keyAgreement</para></listitem>
|
||
+ <listitem><para>keyCertSign</para></listitem>
|
||
+ <listitem><para>cRLSign</para></listitem>
|
||
+ <listitem><para>encipherOnly</para></listitem>
|
||
+ <listitem><para>decipherOnly</para></listitem>
|
||
+ </itemizedlist>
|
||
+ </para>
|
||
+ <para>
|
||
+ A numerical value in the range of a 32bit unsigned
|
||
+ integer can be used as well to cover special use cases.
|
||
+ </para>
|
||
+ <para>
|
||
+ Example: <KU>digitalSignature,keyEncipherment
|
||
+ </para>
|
||
+ </listitem>
|
||
+ </varlistentry>
|
||
+ <varlistentry>
|
||
+ <term><EKU>extended-key-usage</term>
|
||
+ <listitem>
|
||
+ <para>
|
||
+ This option can be used to specify which extended key
|
||
+ usage the certificate should have. The following value
|
||
+ can be used in a comma separated list:
|
||
+ <itemizedlist>
|
||
+ <listitem><para>serverAuth</para></listitem>
|
||
+ <listitem><para>clientAuth</para></listitem>
|
||
+ <listitem><para>codeSigning</para></listitem>
|
||
+ <listitem><para>emailProtection</para></listitem>
|
||
+ <listitem><para>timeStamping</para></listitem>
|
||
+ <listitem><para>OCSPSigning</para></listitem>
|
||
+ <listitem><para>KPClientAuth</para></listitem>
|
||
+ <listitem><para>pkinit</para></listitem>
|
||
+ <listitem><para>msScLogin</para></listitem>
|
||
+ </itemizedlist>
|
||
+ </para>
|
||
+ <para>
|
||
+ Extended key usages which are not listed above can be
|
||
+ specified with their OID in dotted-decimal notation.
|
||
+ </para>
|
||
+ <para>
|
||
+ Example: <EKU>clientAuth,1.3.6.1.5.2.3.4
|
||
+ </para>
|
||
+ </listitem>
|
||
+ </varlistentry>
|
||
+ <varlistentry>
|
||
+ <term><SAN>regular-expression</term>
|
||
+ <listitem>
|
||
+ <para>
|
||
+ To be compatible with the usage of MIT Kerberos this
|
||
+ option will match the Kerberos principals in the PKINIT
|
||
+ or AD NT Principal SAN as <SAN:Principal> does.
|
||
+ </para>
|
||
+ <para>
|
||
+ Example: <SAN>.*@MY\.REALM
|
||
+ </para>
|
||
+ </listitem>
|
||
+ </varlistentry>
|
||
+ <varlistentry>
|
||
+ <term><SAN:Principal>regular-expression</term>
|
||
+ <listitem>
|
||
+ <para>
|
||
+ Match the Kerberos principals in the PKINIT or AD NT
|
||
+ Principal SAN.
|
||
+ </para>
|
||
+ <para>
|
||
+ Example: <SAN:Principal>.*@MY\.REALM
|
||
+ </para>
|
||
+ </listitem>
|
||
+ </varlistentry>
|
||
+ <varlistentry>
|
||
+ <term><SAN:ntPrincipalName>regular-expression</term>
|
||
+ <listitem>
|
||
+ <para>
|
||
+ Match the Kerberos principals from the AD NT Principal
|
||
+ SAN.
|
||
+ </para>
|
||
+ <para>
|
||
+ Example: <SAN:ntPrincipalName>.*@MY.AD.REALM
|
||
+ </para>
|
||
+ </listitem>
|
||
+ </varlistentry>
|
||
+ <varlistentry>
|
||
+ <term><SAN:pkinit>regular-expression</term>
|
||
+ <listitem>
|
||
+ <para>
|
||
+ Match the Kerberos principals from the PKINIT SAN.
|
||
+ </para>
|
||
+ <para>
|
||
+ Example: <SAN:ntPrincipalName>.*@MY\.PKINIT\.REALM
|
||
+ </para>
|
||
+ </listitem>
|
||
+ </varlistentry>
|
||
+ <varlistentry>
|
||
+ <term><SAN:dotted-decimal-oid>regular-expression</term>
|
||
+ <listitem>
|
||
+ <para>
|
||
+ Take the value of the otherName SAN component given by
|
||
+ the OID in dotted-decimal notation, interpret it as
|
||
+ string and try to match it against the regular
|
||
+ expression.
|
||
+ </para>
|
||
+ <para>
|
||
+ Example: <SAN:1.2.3.4>test
|
||
+ </para>
|
||
+ </listitem>
|
||
+ </varlistentry>
|
||
+ <varlistentry>
|
||
+ <term><SAN:otherName>base64-string</term>
|
||
+ <listitem>
|
||
+ <para>
|
||
+ Do a binary match with the base64 encoded blob against
|
||
+ all otherName SAN components. With this option it is
|
||
+ possible to match against custom otherName components
|
||
+ with special encodings which could not be treated as
|
||
+ strings.
|
||
+ </para>
|
||
+ <para>
|
||
+ Example: <SAN:otherName>MTIz
|
||
+ </para>
|
||
+ </listitem>
|
||
+ </varlistentry>
|
||
+ <varlistentry>
|
||
+ <term><SAN:rfc822Name>regular-expression</term>
|
||
+ <listitem>
|
||
+ <para>
|
||
+ Match the value of the rfc822Name SAN.
|
||
+ </para>
|
||
+ <para>
|
||
+ Example: <SAN:rfc822Name>.*@email\.domain
|
||
+ </para>
|
||
+ </listitem>
|
||
+ </varlistentry>
|
||
+ <varlistentry>
|
||
+ <term><SAN:dNSName>regular-expression</term>
|
||
+ <listitem>
|
||
+ <para>
|
||
+ Match the value of the dNSName SAN.
|
||
+ </para>
|
||
+ <para>
|
||
+ Example: <SAN:dNSName>.*\.my\.dns\.domain
|
||
+ </para>
|
||
+ </listitem>
|
||
+ </varlistentry>
|
||
+ <varlistentry>
|
||
+ <term><SAN:x400Address>base64-string</term>
|
||
+ <listitem>
|
||
+ <para>
|
||
+ Binary match the value of the x400Address SAN.
|
||
+ </para>
|
||
+ <para>
|
||
+ Example: <SAN:x400Address>MTIz
|
||
+ </para>
|
||
+ </listitem>
|
||
+ </varlistentry>
|
||
+ <varlistentry>
|
||
+ <term><SAN:directoryName>regular-expression</term>
|
||
+ <listitem>
|
||
+ <para>
|
||
+ Match the value of the directoryName SAN. The same
|
||
+ comments as given for <ISSUER> and <SUBJECT>
|
||
+ apply here as well.
|
||
+ </para>
|
||
+ <para>
|
||
+ Example: <SAN:directoryName>.*,DC=com
|
||
+ </para>
|
||
+ </listitem>
|
||
+ </varlistentry>
|
||
+ <varlistentry>
|
||
+ <term><SAN:ediPartyName>base64-string</term>
|
||
+ <listitem>
|
||
+ <para>
|
||
+ Binary match the value of the ediPartyName SAN.
|
||
+ </para>
|
||
+ <para>
|
||
+ Example: <SAN:ediPartyName>MTIz
|
||
+ </para>
|
||
+ </listitem>
|
||
+ </varlistentry>
|
||
+ <varlistentry>
|
||
+ <term><SAN:uniformResourceIdentifier>regular-expression</term>
|
||
+ <listitem>
|
||
+ <para>
|
||
+ Match the value of the uniformResourceIdentifier SAN.
|
||
+ </para>
|
||
+ <para>
|
||
+ Example: <SAN:uniformResourceIdentifier>URN:.*
|
||
+ </para>
|
||
+ </listitem>
|
||
+ </varlistentry>
|
||
+ <varlistentry>
|
||
+ <term><SAN:iPAddress>regular-expression</term>
|
||
+ <listitem>
|
||
+ <para>
|
||
+ Match the value of the iPAddress SAN.
|
||
+ </para>
|
||
+ <para>
|
||
+ Example: <SAN:iPAddress>192\.168\..*
|
||
+ </para>
|
||
+ </listitem>
|
||
+ </varlistentry>
|
||
+ <varlistentry>
|
||
+ <term><SAN:registeredID>regular-expression</term>
|
||
+ <listitem>
|
||
+ <para>
|
||
+ Match the value of the registeredID SAN as
|
||
+ dotted-decimal string.
|
||
+ </para>
|
||
+ <para>
|
||
+ Example: <SAN:registeredID>1\.2\.3\..*
|
||
+ </para>
|
||
+ </listitem>
|
||
+ </varlistentry>
|
||
+ </variablelist>
|
||
+ </para>
|
||
+ </refsect2>
|
||
+ <refsect2 id='map'>
|
||
+ <title>MAPPING RULE</title>
|
||
+ <para>
|
||
+ The mapping rule is used to associate a certificate with one or more
|
||
+ accounts. A Smartcard with the certificate and the matching private
|
||
+ key can then be used to authenticate as one of those accounts.
|
||
+ </para>
|
||
+ <para>
|
||
+ Currently SSSD basically only supports LDAP to lookup user
|
||
+ information (the exception is the proxy provider which is not of
|
||
+ relevance here). Because of this the mapping rule is based on LDAP
|
||
+ search filter syntax with templates to add certificate content to
|
||
+ the filter. It is expected that the filter will only contain the
|
||
+ specific data needed for the mapping an that the caller will embed
|
||
+ it in another filter to do the actual search. Because of this the
|
||
+ filter string should start and stop with '(' and ')' respectively.
|
||
+ </para>
|
||
+ <para>
|
||
+ In general it is recommended to use attributes from the certificate
|
||
+ and add them to special attributes to the LDAP user object. E.g. the
|
||
+ 'altSecurityIdentities' attribute in AD or the 'ipaCertMapData'
|
||
+ attribute for IPA can be used.
|
||
+ </para>
|
||
+ <para>
|
||
+ This should be preferred to read user specific data from the
|
||
+ certificate like e.g. an email address and search for it in the LDAP
|
||
+ server. The reason is that the user specific data in LDAP might
|
||
+ change for various reasons would would break the mapping. On the
|
||
+ other hand it would be hard to break the mapping on purpose for a
|
||
+ specific user.
|
||
+ </para>
|
||
+ <para>
|
||
+ The templates to add certificate data to the search filter are based
|
||
+ on Python-style formatting strings. They consists of a keyword in
|
||
+ curly braces with an optional sub-component specifier separated by a
|
||
+ '.' or an optional conversion/formatting option separated by a '!'.
|
||
+ Allowed values are:
|
||
+ <variablelist>
|
||
+ <varlistentry>
|
||
+ <term>{issuer_dn[!((ad|ad_x500)|ad_ldap|nss_x500|(nss|nss_ldap))]}</term>
|
||
+ <listitem>
|
||
+ <para>
|
||
+ This template will add the full issuer DN converted to a
|
||
+ string according to RFC 4514. If X.500 ordering (most
|
||
+ specific RDN comes last) an option with the '_x500'
|
||
+ prefix should be used.
|
||
+ </para>
|
||
+ <para>
|
||
+ The conversion options starting with 'ad_' will use
|
||
+ attribute names as used by AD, e.g. 'S' instead of 'ST'.
|
||
+ </para>
|
||
+ <para>
|
||
+ The conversion options starting with 'nss_' will use
|
||
+ attribute names as used by NSS.
|
||
+ </para>
|
||
+ <para>
|
||
+ The default conversion option is 'nss', i.e. attribute
|
||
+ names according to NSS and LDAP/RFC 4514 ordering.
|
||
+ </para>
|
||
+ <para>
|
||
+ Example: (ipacertmapdata=X509:<I>{issuer_dn!ad}<S>{subject_dn!ad})
|
||
+ </para>
|
||
+ </listitem>
|
||
+ </varlistentry>
|
||
+ <varlistentry>
|
||
+ <term>{subject_dn[!((ad|ad_x500)|ad_ldap|nss_x500|(nss|nss_ldap))]}</term>
|
||
+ <listitem>
|
||
+ <para>
|
||
+ This template will add the full subject DN converted to
|
||
+ string according to RFC 4514. If X.500 ordering (most
|
||
+ specific RDN comes last) an option with the '_x500'
|
||
+ prefix should be used.
|
||
+ </para>
|
||
+ <para>
|
||
+ The conversion options starting with 'ad_' will use
|
||
+ attribute names as used by AD, e.g. 'S' instead of 'ST'.
|
||
+ </para>
|
||
+ <para>
|
||
+ The conversion options starting with 'nss_' will use
|
||
+ attribute names as used by NSS.
|
||
+ </para>
|
||
+ <para>
|
||
+ The default conversion option is 'nss', i.e. attribute
|
||
+ names according to NSS and LDAP/RFC 4514 ordering.
|
||
+ </para>
|
||
+ <para>
|
||
+ Example: (ipacertmapdata=X509:<I>{issuer_dn!nss_x500}<S>{subject_dn!nss_x500})
|
||
+ </para>
|
||
+ </listitem>
|
||
+ </varlistentry>
|
||
+ <varlistentry>
|
||
+ <term>{cert[!(bin|base64)]}</term>
|
||
+ <listitem>
|
||
+ <para>
|
||
+ This template will add the whole DER encoded certificate
|
||
+ as a string to the search filter. Depending on the
|
||
+ conversion option the binary certificate is either
|
||
+ converted to an escaped hex sequence '\xx' or base64.
|
||
+ The escaped hex sequence is the default and can e.g. be
|
||
+ used with the LDAP attribute 'userCertificate;binary'.
|
||
+ </para>
|
||
+ <para>
|
||
+ Example: (userCertificate;binary={cert!bin})
|
||
+ </para>
|
||
+ </listitem>
|
||
+ </varlistentry>
|
||
+ <varlistentry>
|
||
+ <term>{subject_principal[.short_name]}</term>
|
||
+ <listitem>
|
||
+ <para>
|
||
+ This template will add the Kerberos principal which is
|
||
+ taken either from the SAN used by pkinit or the one used
|
||
+ by AD. The 'short_name' component represent the first
|
||
+ part of the principal before the '@' sign.
|
||
+ </para>
|
||
+ <para>
|
||
+ Example: (|(userPrincipal={subject_principal})(samAccountName={subject_principal.short_name}))
|
||
+ </para>
|
||
+ </listitem>
|
||
+ </varlistentry>
|
||
+ <varlistentry>
|
||
+ <term>{subject_pkinit_principal[.short_name]}</term>
|
||
+ <listitem>
|
||
+ <para>
|
||
+ This template will add the Kerberos principal which is
|
||
+ given by then SAN used by pkinit. The 'short_name'
|
||
+ component represent the first part of the principal
|
||
+ before the '@' sign.
|
||
+ </para>
|
||
+ <para>
|
||
+ Example: (|(userPrincipal={subject_pkinit_principal})(uid={subject_pkinit_principal.short_name}))
|
||
+ </para>
|
||
+ </listitem>
|
||
+ </varlistentry>
|
||
+ <varlistentry>
|
||
+ <term>{subject_nt_principal[.short_name]}</term>
|
||
+ <listitem>
|
||
+ <para>
|
||
+ This template will add the Kerberos principal which is
|
||
+ given by then SAN used by AD. The 'short_name' component
|
||
+ represent the first part of the principal before the '@'
|
||
+ sign.
|
||
+ </para>
|
||
+ <para>
|
||
+ Example: (|(userPrincipal={subject_principal})(samAccountName={subject_principal.short_name}))
|
||
+ </para>
|
||
+ </listitem>
|
||
+ </varlistentry>
|
||
+ <varlistentry>
|
||
+ <term>{subject_rfc822_name[.short_name]}</term>
|
||
+ <listitem>
|
||
+ <para>
|
||
+ This template will add the string which is stored in the
|
||
+ rfc822Name component of the SAN, typically an email
|
||
+ address. The 'short_name' component represent the first
|
||
+ part of the address before the '@' sign.
|
||
+ </para>
|
||
+ <para>
|
||
+ Example: (|(mail={subject_rfc822_name})(uid={subject_rfc822_name.short_name}))
|
||
+ </para>
|
||
+ </listitem>
|
||
+ </varlistentry>
|
||
+ <varlistentry>
|
||
+ <term>{subject_dns_name[.short_name]}</term>
|
||
+ <listitem>
|
||
+ <para>
|
||
+ This template will add the string which is stored in the
|
||
+ dNSName component of the SAN, typically a fully-qualified host name.
|
||
+ The 'short_name' component represent the first
|
||
+ part of the name before the first '.' sign.
|
||
+ </para>
|
||
+ <para>
|
||
+ Example: (|(fqdn={subject_dns_name})(host={subject_dns_name.short_name}))
|
||
+ </para>
|
||
+ </listitem>
|
||
+ </varlistentry>
|
||
+ <varlistentry>
|
||
+ <term>{subject_uri}</term>
|
||
+ <listitem>
|
||
+ <para>
|
||
+ This template will add the string which is stored in the
|
||
+ uniformResourceIdentifier component of the SAN.
|
||
+ </para>
|
||
+ <para>
|
||
+ Example: (uri={subject_uri})
|
||
+ </para>
|
||
+ </listitem>
|
||
+ </varlistentry>
|
||
+ <varlistentry>
|
||
+ <term>{subject_ip_address}</term>
|
||
+ <listitem>
|
||
+ <para>
|
||
+ This template will add the string which is stored in the
|
||
+ iPAddress component of the SAN.
|
||
+ </para>
|
||
+ <para>
|
||
+ Example: (ip={subject_ip_address})
|
||
+ </para>
|
||
+ </listitem>
|
||
+ </varlistentry>
|
||
+ <varlistentry>
|
||
+ <term>{subject_x400_address}</term>
|
||
+ <listitem>
|
||
+ <para>
|
||
+ This template will add the value which is stored in the
|
||
+ x400Address component of the SAN as escaped hex
|
||
+ sequence.
|
||
+ </para>
|
||
+ <para>
|
||
+ Example: (attr:binary={subject_x400_address})
|
||
+ </para>
|
||
+ </listitem>
|
||
+ </varlistentry>
|
||
+ <varlistentry>
|
||
+ <term>{subject_directory_name[!((ad|ad_x500)|ad_ldap|nss_x500|(nss|nss_ldap))]}</term>
|
||
+ <listitem>
|
||
+ <para>
|
||
+ This template will add the DN string of the value which
|
||
+ is stored in the directoryName component of the SAN.
|
||
+ </para>
|
||
+ <para>
|
||
+ Example: (orig_dn={subject_directory_name})
|
||
+ </para>
|
||
+ </listitem>
|
||
+ </varlistentry>
|
||
+ <varlistentry>
|
||
+ <term>{subject_ediparty_name}</term>
|
||
+ <listitem>
|
||
+ <para>
|
||
+ This template will add the value which is stored in the
|
||
+ ediPartyName component of the SAN as escaped hex
|
||
+ sequence.
|
||
+ </para>
|
||
+ <para>
|
||
+ Example: (attr:binary={subject_ediparty_name})
|
||
+ </para>
|
||
+ </listitem>
|
||
+ </varlistentry>
|
||
+ <varlistentry>
|
||
+ <term>{subject_registered_id}</term>
|
||
+ <listitem>
|
||
+ <para>
|
||
+ This template will add the OID which is stored in the
|
||
+ registeredID component of the SAN as as dotted-decimal
|
||
+ string.
|
||
+ </para>
|
||
+ <para>
|
||
+ Example: (oid={subject_registered_id})
|
||
+ </para>
|
||
+ </listitem>
|
||
+ </varlistentry>
|
||
+ </variablelist>
|
||
+ </para>
|
||
+ </refsect2>
|
||
+ <refsect2 id='domains'>
|
||
+ <title>DOMAIN LIST</title>
|
||
+ <para>
|
||
+ If the domain list is not empty users mapped to a given certificate
|
||
+ are not only searched in the local domain but in the listed domains
|
||
+ as well as long as they are know by SSSD. Domains not know to SSSD
|
||
+ will be ignored.
|
||
+ </para>
|
||
+ </refsect2>
|
||
+ </refsect1>
|
||
+</refentry>
|
||
+</reference>
|
||
diff --git a/src/tests/cmocka/test_certmap.c b/src/tests/cmocka/test_certmap.c
|
||
new file mode 100644
|
||
index 0000000000000000000000000000000000000000..c998443d086eaa72cc2a05c38ddfc5ba590a1ce7
|
||
--- /dev/null
|
||
+++ b/src/tests/cmocka/test_certmap.c
|
||
@@ -0,0 +1,1443 @@
|
||
+/*
|
||
+ SSSD
|
||
+
|
||
+ certmap - Tests for SSSD's certificate mapping library
|
||
+
|
||
+ Authors:
|
||
+ Sumit Bose <sbose@redhat.com>
|
||
+
|
||
+ Copyright (C) 2017 Red Hat
|
||
+
|
||
+ This program is free software; you can redistribute it and/or modify
|
||
+ it under the terms of the GNU General Public License as published by
|
||
+ the Free Software Foundation; either version 3 of the License, or
|
||
+ (at your option) any later version.
|
||
+
|
||
+ This program is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
+ GNU General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU General Public License
|
||
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
+*/
|
||
+
|
||
+#include <stdarg.h>
|
||
+#include <stddef.h>
|
||
+#include <setjmp.h>
|
||
+#include <cmocka.h>
|
||
+#include <popt.h>
|
||
+
|
||
+#include "lib/certmap/sss_certmap.h"
|
||
+#include "lib/certmap/sss_certmap_int.h"
|
||
+
|
||
+#include "util/crypto/sss_crypto.h"
|
||
+
|
||
+#include "tests/cmocka/common_mock.h"
|
||
+#include "tests/common.h"
|
||
+
|
||
+#ifdef HAVE_NSS
|
||
+#include "util/crypto/nss/nss_util.h"
|
||
+#endif
|
||
+
|
||
+struct priv_sss_debug {
|
||
+ int level;
|
||
+};
|
||
+
|
||
+void ext_debug(void *private, const char *file, long line, const char *function,
|
||
+ const char *format, ...)
|
||
+{
|
||
+ va_list ap;
|
||
+ struct priv_sss_debug *data = private;
|
||
+ int level = SSSDBG_OP_FAILURE;
|
||
+
|
||
+ if (data != NULL) {
|
||
+ level = data->level;
|
||
+ }
|
||
+
|
||
+ if (DEBUG_IS_SET(level)) {
|
||
+ va_start(ap, format);
|
||
+ sss_vdebug_fn(file, line, function, level, APPEND_LINE_FEED,
|
||
+ format, ap);
|
||
+ va_end(ap);
|
||
+ }
|
||
+}
|
||
+
|
||
+static void test_sss_certmap_init(void **state)
|
||
+{
|
||
+ int ret;
|
||
+ struct sss_certmap_ctx *ctx;
|
||
+
|
||
+ ret = sss_certmap_init(NULL, ext_debug, NULL, NULL);
|
||
+ assert_int_equal(ret, EINVAL);
|
||
+
|
||
+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx);
|
||
+ assert_int_equal(ret, EOK);
|
||
+
|
||
+ sss_certmap_free_ctx(ctx);
|
||
+}
|
||
+
|
||
+static struct sss_certmap_ctx *setup_prio(const int *l)
|
||
+{
|
||
+ int ret;
|
||
+ size_t c;
|
||
+ struct sss_certmap_ctx *ctx;
|
||
+
|
||
+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx);
|
||
+ assert_int_equal(ret, EOK);
|
||
+ assert_non_null(ctx);
|
||
+
|
||
+ for (c = 0; c < 10; c++) {
|
||
+ ret = sss_certmap_add_rule(ctx, l[c], NULL, NULL, NULL);
|
||
+ assert_int_equal(ret, EOK);
|
||
+ }
|
||
+
|
||
+ return ctx;
|
||
+}
|
||
+
|
||
+static void test_sss_certmap_add_rule(void **state)
|
||
+{
|
||
+ struct sss_certmap_ctx *ctx;
|
||
+ int i;
|
||
+ struct priority_list *p;
|
||
+ struct priority_list *last;
|
||
+ size_t c;
|
||
+
|
||
+ const int tests_a[][10] = {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
|
||
+ {9, 8, 7, 6, 5, 4, 3, 2, 1, 0},
|
||
+ {1, 3, 5 ,7, 9, 0, 2, 4, 6, 8},
|
||
+ {0, 2, 4, 6, 8, 1, 3, 5, 7, 9},
|
||
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
|
||
+
|
||
+ const int tests_b[][10] = {{0, 0, 0, 0, 1, 1, 1, 2, 2, 2},
|
||
+ {2, 2, 2, 1, 1, 1, 0, 0, 0, 0},
|
||
+ {0, 1, 2, 0, 1, 2, 0, 1, 2, 0},
|
||
+ {0, 2, 1, 0, 2, 1, 0, 2, 1, 0},
|
||
+ {0, 1, 2, 0, 2, 1, 0, 0, 1, 2},
|
||
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
|
||
+
|
||
+ for (c = 0; tests_a[c][0] != 0 || tests_a[c][9] != 0; c++) {
|
||
+ ctx = setup_prio(tests_a[0]);
|
||
+ assert_non_null(ctx);
|
||
+ i = 0;
|
||
+ for (p = ctx->prio_list; p != NULL; p = p->next) {
|
||
+ assert_int_equal(i, p->priority);
|
||
+ assert_non_null(p->rule_list);
|
||
+ assert_int_equal(i, p->rule_list->priority);
|
||
+ assert_null(p->rule_list->prev);
|
||
+ assert_null(p->rule_list->next);
|
||
+ i++;
|
||
+ }
|
||
+
|
||
+ i = 9;
|
||
+ for (last = ctx->prio_list; last->next != NULL; last = last->next);
|
||
+ for (p = last; p != NULL; p = p->prev) {
|
||
+ assert_int_equal(i, p->priority);
|
||
+ assert_int_equal(i, p->rule_list->priority);
|
||
+ i--;
|
||
+ }
|
||
+
|
||
+ sss_certmap_free_ctx(ctx);
|
||
+ }
|
||
+ for (c = 0; tests_b[c][0] != 0 || tests_b[c][9] != 0; c++) {
|
||
+ ctx = setup_prio(tests_b[0]);
|
||
+ assert_non_null(ctx);
|
||
+ i = 0;
|
||
+ for (p = ctx->prio_list; p != NULL; p = p->next) {
|
||
+ assert_int_equal(i, p->priority);
|
||
+ assert_non_null(p->rule_list);
|
||
+ assert_int_equal(i, p->rule_list->priority);
|
||
+ assert_null(p->rule_list->prev);
|
||
+ assert_non_null(p->rule_list->next);
|
||
+ assert_ptr_equal(p->rule_list, p->rule_list->next->prev);
|
||
+ assert_non_null(p->rule_list->next->next);
|
||
+ assert_ptr_equal(p->rule_list->next,
|
||
+ p->rule_list->next->next->prev);
|
||
+ if (i == 0) {
|
||
+ assert_non_null(p->rule_list->next->next->next);
|
||
+ assert_ptr_equal(p->rule_list->next->next,
|
||
+ p->rule_list->next->next->next->prev);
|
||
+ assert_null(p->rule_list->next->next->next->next);
|
||
+ } else {
|
||
+ assert_null(p->rule_list->next->next->next);
|
||
+ }
|
||
+ i++;
|
||
+ }
|
||
+ sss_certmap_free_ctx(ctx);
|
||
+ }
|
||
+}
|
||
+
|
||
+static void test_sss_certmap_add_matching_rule(void **state)
|
||
+{
|
||
+ struct sss_certmap_ctx *ctx;
|
||
+ int ret;
|
||
+
|
||
+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx);
|
||
+ assert_int_equal(ret, EOK);
|
||
+ assert_non_null(ctx);
|
||
+ assert_null(ctx->prio_list);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 1, "fsdf", NULL, NULL);
|
||
+ assert_int_equal(ret, EINVAL);
|
||
+ assert_null(ctx->prio_list);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 1, "FDSF:fsdf", NULL, NULL);
|
||
+ assert_int_equal(ret, ESRCH);
|
||
+ assert_null(ctx->prio_list);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 1, "<rgerge>", NULL, NULL);
|
||
+ assert_int_equal(ret, EINVAL);
|
||
+ assert_null(ctx->prio_list);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 1, "KRB5:<rgerge>", NULL, NULL);
|
||
+ assert_int_equal(ret, EINVAL);
|
||
+ assert_null(ctx->prio_list);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 1, "<ISSUER>", NULL, NULL);
|
||
+ assert_int_equal(ret, EINVAL);
|
||
+ assert_null(ctx->prio_list);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 1, "<SUBJECT>", NULL, NULL);
|
||
+ assert_int_equal(ret, EINVAL);
|
||
+ assert_null(ctx->prio_list);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 1, "<KU>", NULL, NULL);
|
||
+ assert_int_equal(ret, EINVAL);
|
||
+ assert_null(ctx->prio_list);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 1, "<KU>ddqwdq", NULL, NULL);
|
||
+ assert_int_equal(ret, EINVAL);
|
||
+ assert_null(ctx->prio_list);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 1, "<KU>digitalSignature,dddq", NULL, NULL);
|
||
+ assert_int_equal(ret, EINVAL);
|
||
+ assert_null(ctx->prio_list);
|
||
+
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 1, "<EKU>", NULL, NULL);
|
||
+ assert_int_equal(ret, EINVAL);
|
||
+ assert_null(ctx->prio_list);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 1, "<EKU>dwqwqw", NULL, NULL);
|
||
+ assert_int_equal(ret, EINVAL);
|
||
+ assert_null(ctx->prio_list);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 1, "<EKU>.", NULL, NULL);
|
||
+ assert_int_equal(ret, EINVAL);
|
||
+ assert_null(ctx->prio_list);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 1, "<EKU>.1.2.3", NULL, NULL);
|
||
+ assert_int_equal(ret, EINVAL);
|
||
+ assert_null(ctx->prio_list);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 1, "<EKU>1.2.3.", NULL, NULL);
|
||
+ assert_int_equal(ret, EINVAL);
|
||
+ assert_null(ctx->prio_list);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 1, "<EKU>1.a.3", NULL, NULL);
|
||
+ assert_int_equal(ret, EINVAL);
|
||
+ assert_null(ctx->prio_list);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 1, "<SAN:fwfwef>", NULL, NULL);
|
||
+ assert_int_equal(ret, EINVAL);
|
||
+ assert_null(ctx->prio_list);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 1, "<SAN:rfc822Name", NULL, NULL);
|
||
+ assert_int_equal(ret, EINVAL);
|
||
+ assert_null(ctx->prio_list);
|
||
+
|
||
+ /* invalid base64 input */
|
||
+ ret = sss_certmap_add_rule(ctx, 1, "<SAN:ediPartyName>...", NULL, NULL);
|
||
+ assert_int_equal(ret, EINVAL);
|
||
+ assert_null(ctx->prio_list);
|
||
+
|
||
+ /* invalid OID input */
|
||
+ ret = sss_certmap_add_rule(ctx, 1, "<SAN:.>dqq", NULL, NULL);
|
||
+ assert_int_equal(ret, EINVAL);
|
||
+ assert_null(ctx->prio_list);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 1, "<SAN:.1>dqq", NULL, NULL);
|
||
+ assert_int_equal(ret, EINVAL);
|
||
+ assert_null(ctx->prio_list);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 1, "<SAN:1.>dqq", NULL, NULL);
|
||
+ assert_int_equal(ret, EINVAL);
|
||
+ assert_null(ctx->prio_list);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 1, "<SAN:11>dqq", NULL, NULL);
|
||
+ assert_int_equal(ret, EINVAL);
|
||
+ assert_null(ctx->prio_list);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 1, "<ISSUER>a", NULL, NULL);
|
||
+ assert_int_equal(ret, 0);
|
||
+ assert_non_null(ctx->prio_list);
|
||
+ assert_non_null(ctx->prio_list->rule_list);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule);
|
||
+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r,
|
||
+ relation_and);
|
||
+ assert_null(ctx->prio_list->rule_list->parsed_match_rule->subject);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->issuer);
|
||
+ assert_string_equal("a",
|
||
+ ctx->prio_list->rule_list->parsed_match_rule->issuer->val);
|
||
+ talloc_free(ctx);
|
||
+
|
||
+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx);
|
||
+ assert_int_equal(ret, EOK);
|
||
+ assert_non_null(ctx);
|
||
+ assert_null(ctx->prio_list);
|
||
+ ret = sss_certmap_add_rule(ctx, 1, "&&<ISSUER>a", NULL, NULL);
|
||
+ assert_int_equal(ret, 0);
|
||
+ assert_non_null(ctx->prio_list);
|
||
+ assert_non_null(ctx->prio_list->rule_list);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule);
|
||
+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r,
|
||
+ relation_and);
|
||
+ assert_null(ctx->prio_list->rule_list->parsed_match_rule->subject);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->issuer);
|
||
+ assert_string_equal("a",
|
||
+ ctx->prio_list->rule_list->parsed_match_rule->issuer->val);
|
||
+ talloc_free(ctx);
|
||
+
|
||
+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx);
|
||
+ assert_int_equal(ret, EOK);
|
||
+ assert_non_null(ctx);
|
||
+ assert_null(ctx->prio_list);
|
||
+ ret = sss_certmap_add_rule(ctx, 1, "KRB5:||<ISSUER>a", NULL, NULL);
|
||
+ assert_int_equal(ret, 0);
|
||
+ assert_non_null(ctx->prio_list);
|
||
+ assert_non_null(ctx->prio_list->rule_list);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule);
|
||
+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r,
|
||
+ relation_or);
|
||
+ assert_null(ctx->prio_list->rule_list->parsed_match_rule->subject);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->issuer);
|
||
+ assert_string_equal("a",
|
||
+ ctx->prio_list->rule_list->parsed_match_rule->issuer->val);
|
||
+ talloc_free(ctx);
|
||
+
|
||
+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx);
|
||
+ assert_int_equal(ret, EOK);
|
||
+ assert_non_null(ctx);
|
||
+ assert_null(ctx->prio_list);
|
||
+ ret = sss_certmap_add_rule(ctx, 1, "KRB5:<ISSUER>a<SUBJECT>b", NULL, NULL);
|
||
+ assert_int_equal(ret, 0);
|
||
+ assert_non_null(ctx->prio_list);
|
||
+ assert_non_null(ctx->prio_list->rule_list);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule);
|
||
+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r,
|
||
+ relation_and);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->subject);
|
||
+ assert_string_equal("b",
|
||
+ ctx->prio_list->rule_list->parsed_match_rule->subject->val);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->issuer);
|
||
+ assert_string_equal("a",
|
||
+ ctx->prio_list->rule_list->parsed_match_rule->issuer->val);
|
||
+ talloc_free(ctx);
|
||
+
|
||
+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx);
|
||
+ assert_int_equal(ret, EOK);
|
||
+ assert_non_null(ctx);
|
||
+ assert_null(ctx->prio_list);
|
||
+ ret = sss_certmap_add_rule(ctx, 1000,
|
||
+ "KRB5:<ISSUER>a<SUBJECT>b<ISSUER>c<SUBJECT>d",
|
||
+ NULL, NULL);
|
||
+ assert_int_equal(ret, 0);
|
||
+ assert_non_null(ctx->prio_list);
|
||
+ assert_non_null(ctx->prio_list->rule_list);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule);
|
||
+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r,
|
||
+ relation_and);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->subject);
|
||
+ assert_string_equal("d",
|
||
+ ctx->prio_list->rule_list->parsed_match_rule->subject->val);
|
||
+ assert_string_equal("b",
|
||
+ ctx->prio_list->rule_list->parsed_match_rule->subject->next->val);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->issuer);
|
||
+ assert_string_equal("c",
|
||
+ ctx->prio_list->rule_list->parsed_match_rule->issuer->val);
|
||
+ assert_string_equal("a",
|
||
+ ctx->prio_list->rule_list->parsed_match_rule->issuer->next->val);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 99,
|
||
+ "KRB5:<ISSUER>a<SUBJECT>b"
|
||
+ "<KU>dataEncipherment,cRLSign<ISSUER>c"
|
||
+ "<SUBJECT>d",
|
||
+ NULL, NULL);
|
||
+ assert_int_equal(ret, 0);
|
||
+ assert_non_null(ctx->prio_list);
|
||
+ assert_non_null(ctx->prio_list->rule_list);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule);
|
||
+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r,
|
||
+ relation_and);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->subject);
|
||
+ assert_string_equal("d",
|
||
+ ctx->prio_list->rule_list->parsed_match_rule->subject->val);
|
||
+ assert_string_equal("b",
|
||
+ ctx->prio_list->rule_list->parsed_match_rule->subject->next->val);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->issuer);
|
||
+ assert_string_equal("c",
|
||
+ ctx->prio_list->rule_list->parsed_match_rule->issuer->val);
|
||
+ assert_string_equal("a",
|
||
+ ctx->prio_list->rule_list->parsed_match_rule->issuer->next->val);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->ku);
|
||
+ assert_int_equal(SSS_KU_CRL_SIGN|SSS_KU_DATA_ENCIPHERMENT,
|
||
+ ctx->prio_list->rule_list->parsed_match_rule->ku->ku);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 98,
|
||
+ "KRB5:<ISSUER>a<SUBJECT>b"
|
||
+ "<KU>dataEncipherment,cRLSign<ISSUER>c"
|
||
+ "<EKU>clientAuth,emailProtection"
|
||
+ "<SUBJECT>d",
|
||
+ NULL, NULL);
|
||
+ assert_int_equal(ret, 0);
|
||
+ assert_non_null(ctx->prio_list);
|
||
+ assert_non_null(ctx->prio_list->rule_list);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule);
|
||
+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r,
|
||
+ relation_and);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->subject);
|
||
+ assert_string_equal("d",
|
||
+ ctx->prio_list->rule_list->parsed_match_rule->subject->val);
|
||
+ assert_string_equal("b",
|
||
+ ctx->prio_list->rule_list->parsed_match_rule->subject->next->val);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->issuer);
|
||
+ assert_string_equal("c",
|
||
+ ctx->prio_list->rule_list->parsed_match_rule->issuer->val);
|
||
+ assert_string_equal("a",
|
||
+ ctx->prio_list->rule_list->parsed_match_rule->issuer->next->val);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->ku);
|
||
+ assert_int_equal(SSS_KU_CRL_SIGN|SSS_KU_DATA_ENCIPHERMENT,
|
||
+ ctx->prio_list->rule_list->parsed_match_rule->ku->ku);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->eku);
|
||
+ assert_true(string_in_list("1.3.6.1.5.5.7.3.2",
|
||
+ discard_const(
|
||
+ ctx->prio_list->rule_list->parsed_match_rule->eku->eku_oid_list),
|
||
+ true));
|
||
+ assert_true(string_in_list("1.3.6.1.5.5.7.3.4",
|
||
+ discard_const(
|
||
+ ctx->prio_list->rule_list->parsed_match_rule->eku->eku_oid_list),
|
||
+ true));
|
||
+ assert_null(
|
||
+ ctx->prio_list->rule_list->parsed_match_rule->eku->eku_oid_list[2]);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 97,
|
||
+ "KRB5:<EKU>clientAuth,1.2.3,emailProtection",
|
||
+ NULL, NULL);
|
||
+ assert_int_equal(ret, 0);
|
||
+ assert_non_null(ctx->prio_list);
|
||
+ assert_non_null(ctx->prio_list->rule_list);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule);
|
||
+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r,
|
||
+ relation_and);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->eku);
|
||
+ assert_true(string_in_list("1.3.6.1.5.5.7.3.2",
|
||
+ discard_const(
|
||
+ ctx->prio_list->rule_list->parsed_match_rule->eku->eku_oid_list),
|
||
+ true));
|
||
+ assert_true(string_in_list("1.3.6.1.5.5.7.3.4",
|
||
+ discard_const(
|
||
+ ctx->prio_list->rule_list->parsed_match_rule->eku->eku_oid_list),
|
||
+ true));
|
||
+ assert_true(string_in_list("1.2.3",
|
||
+ discard_const(
|
||
+ ctx->prio_list->rule_list->parsed_match_rule->eku->eku_oid_list),
|
||
+ true));
|
||
+ assert_null(
|
||
+ ctx->prio_list->rule_list->parsed_match_rule->eku->eku_oid_list[3]);
|
||
+
|
||
+ /* SAN tests */
|
||
+ ret = sss_certmap_add_rule(ctx, 89, "KRB5:<SAN>abc", NULL, NULL);
|
||
+ assert_int_equal(ret, 0);
|
||
+ assert_non_null(ctx->prio_list);
|
||
+ assert_non_null(ctx->prio_list->rule_list);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule);
|
||
+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r,
|
||
+ relation_and);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->san);
|
||
+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->san->san_opt,
|
||
+ SAN_PRINCIPAL);
|
||
+ assert_string_equal(ctx->prio_list->rule_list->parsed_match_rule->san->val,
|
||
+ "abc");
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 88, "KRB5:<SAN:dnsName>def", NULL, NULL);
|
||
+ assert_int_equal(ret, 0);
|
||
+ assert_non_null(ctx->prio_list);
|
||
+ assert_non_null(ctx->prio_list->rule_list);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule);
|
||
+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r,
|
||
+ relation_and);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->san);
|
||
+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->san->san_opt,
|
||
+ SAN_DNS_NAME);
|
||
+ assert_string_equal(ctx->prio_list->rule_list->parsed_match_rule->san->val,
|
||
+ "def");
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 87, "KRB5:<SAN:x400Address>aGlq",
|
||
+ NULL, NULL);
|
||
+ assert_int_equal(ret, 0);
|
||
+ assert_non_null(ctx->prio_list);
|
||
+ assert_non_null(ctx->prio_list->rule_list);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule);
|
||
+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r,
|
||
+ relation_and);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->san);
|
||
+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->san->san_opt,
|
||
+ SAN_X400_ADDRESS);
|
||
+ assert_int_equal(
|
||
+ ctx->prio_list->rule_list->parsed_match_rule->san->bin_val_len,
|
||
+ 3);
|
||
+ assert_memory_equal(
|
||
+ ctx->prio_list->rule_list->parsed_match_rule->san->bin_val,
|
||
+ "hij", 3);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 86, "KRB5:<SAN:1.2.3.4>klm",
|
||
+ NULL, NULL);
|
||
+ assert_int_equal(ret, 0);
|
||
+ assert_non_null(ctx->prio_list);
|
||
+ assert_non_null(ctx->prio_list->rule_list);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule);
|
||
+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->r,
|
||
+ relation_and);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_match_rule->san);
|
||
+ assert_int_equal(ctx->prio_list->rule_list->parsed_match_rule->san->san_opt,
|
||
+ SAN_STRING_OTHER_NAME);
|
||
+ assert_string_equal(ctx->prio_list->rule_list->parsed_match_rule->san->val,
|
||
+ "klm");
|
||
+ assert_string_equal("1.2.3.4",
|
||
+ ctx->prio_list->rule_list->parsed_match_rule->san->str_other_name_oid);
|
||
+
|
||
+ talloc_free(ctx);
|
||
+}
|
||
+
|
||
+static void test_check_ad_attr_name(void **state)
|
||
+{
|
||
+ char *res;
|
||
+
|
||
+ res = check_ad_attr_name(NULL, NULL);
|
||
+ assert_null(res);
|
||
+
|
||
+ res = check_ad_attr_name(NULL, "");
|
||
+ assert_null(res);
|
||
+
|
||
+ res = check_ad_attr_name(NULL, "dsddqwdas");
|
||
+ assert_null(res);
|
||
+
|
||
+ res = check_ad_attr_name(NULL, "dsddq=wdas");
|
||
+ assert_null(res);
|
||
+
|
||
+ res = check_ad_attr_name(NULL, "CN=abc");
|
||
+ assert_null(res);
|
||
+
|
||
+ res = check_ad_attr_name(NULL, "O=xyz");
|
||
+ assert_null(res);
|
||
+
|
||
+ res = check_ad_attr_name(NULL, "ST=def");
|
||
+ assert_non_null(res);
|
||
+ assert_string_equal(res, "S=def");
|
||
+ talloc_free(res);
|
||
+}
|
||
+
|
||
+const uint8_t test_cert_der[] = {
|
||
+0x30, 0x82, 0x04, 0x09, 0x30, 0x82, 0x02, 0xf1, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x09,
|
||
+0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30,
|
||
+0x34, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x09, 0x49, 0x50, 0x41, 0x2e,
|
||
+0x44, 0x45, 0x56, 0x45, 0x4c, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x15,
|
||
+0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68,
|
||
+0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x35, 0x30, 0x34, 0x32, 0x38, 0x31,
|
||
+0x30, 0x32, 0x31, 0x31, 0x31, 0x5a, 0x17, 0x0d, 0x31, 0x37, 0x30, 0x34, 0x32, 0x38, 0x31, 0x30,
|
||
+0x32, 0x31, 0x31, 0x31, 0x5a, 0x30, 0x32, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a,
|
||
+0x0c, 0x09, 0x49, 0x50, 0x41, 0x2e, 0x44, 0x45, 0x56, 0x45, 0x4c, 0x31, 0x1c, 0x30, 0x1a, 0x06,
|
||
+0x03, 0x55, 0x04, 0x03, 0x0c, 0x13, 0x69, 0x70, 0x61, 0x2d, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x2e,
|
||
+0x69, 0x70, 0x61, 0x2e, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06,
|
||
+0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f,
|
||
+0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xb2, 0x32, 0x92, 0xab, 0x47, 0xb8,
|
||
+0x0c, 0x13, 0x54, 0x4a, 0x1f, 0x1e, 0x29, 0x06, 0xff, 0xd0, 0x50, 0xcb, 0xf7, 0x5f, 0x79, 0x91,
|
||
+0x65, 0xb1, 0x39, 0x01, 0x83, 0x6a, 0xad, 0x9e, 0x77, 0x3b, 0xf3, 0x0d, 0xd7, 0xb9, 0xf6, 0xdc,
|
||
+0x9e, 0x4a, 0x49, 0xa7, 0xd0, 0x66, 0x72, 0xcc, 0xbf, 0x77, 0xd6, 0xde, 0xa9, 0xfe, 0x67, 0x96,
|
||
+0xcc, 0x49, 0xf1, 0x37, 0x23, 0x2e, 0xc4, 0x50, 0xf4, 0xeb, 0xba, 0x62, 0xd4, 0x23, 0x4d, 0xf3,
|
||
+0x37, 0x38, 0x82, 0xee, 0x3b, 0x3f, 0x2c, 0xd0, 0x80, 0x9b, 0x17, 0xaa, 0x9b, 0xeb, 0xa6, 0xdd,
|
||
+0xf6, 0x15, 0xff, 0x06, 0xb2, 0xce, 0xff, 0xdf, 0x8a, 0x9e, 0x95, 0x85, 0x49, 0x1f, 0x84, 0xfd,
|
||
+0x81, 0x26, 0xce, 0x06, 0x32, 0x0d, 0x36, 0xca, 0x7c, 0x15, 0x81, 0x68, 0x6b, 0x8f, 0x3e, 0xb3,
|
||
+0xa2, 0xfc, 0xae, 0xaf, 0xc2, 0x44, 0x58, 0x15, 0x95, 0x40, 0xfc, 0x56, 0x19, 0x91, 0x80, 0xed,
|
||
+0x42, 0x11, 0x66, 0x04, 0xef, 0x3c, 0xe0, 0x76, 0x33, 0x4b, 0x83, 0xfa, 0x7e, 0xb4, 0x47, 0xdc,
|
||
+0xfb, 0xed, 0x46, 0xa5, 0x8d, 0x0a, 0x66, 0x87, 0xa5, 0xef, 0x7b, 0x74, 0x62, 0xac, 0xbe, 0x73,
|
||
+0x36, 0xc9, 0xb4, 0xfe, 0x20, 0xc4, 0x81, 0xf3, 0xfe, 0x78, 0x19, 0xa8, 0xd0, 0xaf, 0x7f, 0x81,
|
||
+0x72, 0x24, 0x61, 0xd9, 0x76, 0x93, 0xe3, 0x0b, 0xd2, 0x4f, 0x19, 0x17, 0x33, 0x57, 0xd4, 0x82,
|
||
+0xb0, 0xf1, 0xa8, 0x03, 0xf6, 0x01, 0x99, 0xa9, 0xb8, 0x8c, 0x83, 0xc9, 0xba, 0x19, 0x87, 0xea,
|
||
+0xd6, 0x3b, 0x06, 0xeb, 0x4c, 0xf7, 0xf1, 0xe5, 0x28, 0xa9, 0x10, 0xb6, 0x46, 0xde, 0xe1, 0xe1,
|
||
+0x3f, 0xc1, 0xcc, 0x72, 0xbe, 0x2a, 0x43, 0xc6, 0xf6, 0xd0, 0xb5, 0xa0, 0xc4, 0x24, 0x6e, 0x4f,
|
||
+0xbd, 0xec, 0x22, 0x8a, 0x07, 0x11, 0x3d, 0xf9, 0xd3, 0x15, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3,
|
||
+0x82, 0x01, 0x26, 0x30, 0x82, 0x01, 0x22, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18,
|
||
+0x30, 0x16, 0x80, 0x14, 0xf2, 0x9d, 0x42, 0x4e, 0x0f, 0xc4, 0x48, 0x25, 0x58, 0x2f, 0x1c, 0xce,
|
||
+0x0f, 0xa1, 0x3f, 0x22, 0xc8, 0x55, 0xc8, 0x91, 0x30, 0x3b, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
|
||
+0x05, 0x07, 0x01, 0x01, 0x04, 0x2f, 0x30, 0x2d, 0x30, 0x2b, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
|
||
+0x05, 0x07, 0x30, 0x01, 0x86, 0x1f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x69, 0x70, 0x61,
|
||
+0x2d, 0x63, 0x61, 0x2e, 0x69, 0x70, 0x61, 0x2e, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x2f, 0x63, 0x61,
|
||
+0x2f, 0x6f, 0x63, 0x73, 0x70, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04,
|
||
+0x04, 0x03, 0x02, 0x04, 0xf0, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14,
|
||
+0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
|
||
+0x05, 0x07, 0x03, 0x02, 0x30, 0x74, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x6d, 0x30, 0x6b, 0x30,
|
||
+0x69, 0xa0, 0x31, 0xa0, 0x2f, 0x86, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x69, 0x70,
|
||
+0x61, 0x2d, 0x63, 0x61, 0x2e, 0x69, 0x70, 0x61, 0x2e, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x2f, 0x69,
|
||
+0x70, 0x61, 0x2f, 0x63, 0x72, 0x6c, 0x2f, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x43, 0x52, 0x4c,
|
||
+0x2e, 0x62, 0x69, 0x6e, 0xa2, 0x34, 0xa4, 0x32, 0x30, 0x30, 0x31, 0x0e, 0x30, 0x0c, 0x06, 0x03,
|
||
+0x55, 0x04, 0x0a, 0x0c, 0x05, 0x69, 0x70, 0x61, 0x63, 0x61, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03,
|
||
+0x55, 0x04, 0x03, 0x0c, 0x15, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
|
||
+0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
|
||
+0x0e, 0x04, 0x16, 0x04, 0x14, 0x2d, 0x2b, 0x3f, 0xcb, 0xf5, 0xb2, 0xff, 0x32, 0x2c, 0xa8, 0xc2,
|
||
+0x1c, 0xdd, 0xbd, 0x8c, 0x80, 0x1e, 0xdd, 0x31, 0x82, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
|
||
+0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x9a, 0x47, 0x2e,
|
||
+0x50, 0xa7, 0x4d, 0x1d, 0x53, 0x0f, 0xc9, 0x71, 0x42, 0x0c, 0xe5, 0xda, 0x7d, 0x49, 0x64, 0xe7,
|
||
+0xab, 0xc8, 0xdf, 0xdf, 0x02, 0xc1, 0x87, 0xd1, 0x5b, 0xde, 0xda, 0x6f, 0x2b, 0xe4, 0xf0, 0xbe,
|
||
+0xba, 0x09, 0xdf, 0x02, 0x85, 0x0b, 0x8a, 0xe6, 0x9b, 0x06, 0x7d, 0x69, 0x38, 0x6c, 0x72, 0xff,
|
||
+0x4c, 0x7b, 0x2a, 0x0d, 0x3f, 0x23, 0x2f, 0x16, 0x46, 0xff, 0x05, 0x93, 0xb0, 0xea, 0x24, 0x28,
|
||
+0xd7, 0x12, 0xa1, 0x57, 0xb8, 0x59, 0x19, 0x25, 0xf3, 0x43, 0x0a, 0xd3, 0xfd, 0x0f, 0x37, 0x8d,
|
||
+0xb8, 0xca, 0x15, 0xe7, 0x48, 0x8a, 0xa0, 0xc7, 0xc7, 0x4b, 0x7f, 0x01, 0x3c, 0x58, 0xd7, 0x37,
|
||
+0xe5, 0xff, 0x7d, 0x2b, 0x01, 0xac, 0x0d, 0x9f, 0x51, 0x6a, 0xe5, 0x40, 0x24, 0xe6, 0x5e, 0x55,
|
||
+0x0d, 0xf7, 0xb8, 0x2f, 0x42, 0xac, 0x6d, 0xe5, 0x29, 0x6b, 0xc6, 0x0b, 0xa4, 0xbf, 0x19, 0xbd,
|
||
+0x39, 0x27, 0xee, 0xfe, 0xc5, 0xb3, 0xdb, 0x62, 0xd4, 0xbe, 0xd2, 0x47, 0xba, 0x96, 0x30, 0x5a,
|
||
+0xfd, 0x62, 0x00, 0xb8, 0x27, 0x5d, 0x2f, 0x3a, 0x94, 0x0b, 0x95, 0x35, 0x85, 0x40, 0x2c, 0xbc,
|
||
+0x67, 0xdf, 0x8a, 0xf9, 0xf1, 0x7b, 0x19, 0x96, 0x3e, 0x42, 0x48, 0x13, 0x23, 0x04, 0x95, 0xa9,
|
||
+0x6b, 0x11, 0x33, 0x81, 0x47, 0x5a, 0x83, 0x72, 0xf6, 0x20, 0xfa, 0x8e, 0x41, 0x7b, 0x8f, 0x77,
|
||
+0x47, 0x7c, 0xc7, 0x5d, 0x46, 0xf4, 0x4f, 0xfd, 0x81, 0x0a, 0xae, 0x39, 0x27, 0xb6, 0x6a, 0x26,
|
||
+0x63, 0xb1, 0xd3, 0xbf, 0x55, 0x83, 0x82, 0x9b, 0x36, 0x6c, 0x33, 0x64, 0x0f, 0x50, 0xc0, 0x55,
|
||
+0x94, 0x13, 0xc3, 0x85, 0xf4, 0xd5, 0x71, 0x65, 0xd0, 0xc0, 0xdd, 0xfc, 0xe6, 0xec, 0x9c, 0x5b,
|
||
+0xf0, 0x11, 0xb5, 0x2c, 0xf3, 0x48, 0xc1, 0x36, 0x8c, 0xa2, 0x96, 0x48, 0x84};
|
||
+
|
||
+const uint8_t test_cert2_der[] = {
|
||
+0x30, 0x82, 0x06, 0x98, 0x30, 0x82, 0x05, 0x80, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x0a, 0x61,
|
||
+0x22, 0x88, 0xc2, 0x00, 0x00, 0x00, 0x00, 0x02, 0xa6, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
|
||
+0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x15, 0x30, 0x13, 0x06, 0x0a,
|
||
+0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x05, 0x64, 0x65, 0x76, 0x65,
|
||
+0x6c, 0x31, 0x12, 0x30, 0x10, 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01,
|
||
+0x19, 0x16, 0x02, 0x61, 0x64, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0f,
|
||
+0x61, 0x64, 0x2d, 0x41, 0x44, 0x2d, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x2d, 0x43, 0x41, 0x30,
|
||
+0x1e, 0x17, 0x0d, 0x31, 0x36, 0x31, 0x31, 0x31, 0x31, 0x31, 0x33, 0x35, 0x31, 0x31, 0x31, 0x5a,
|
||
+0x17, 0x0d, 0x31, 0x37, 0x31, 0x31, 0x31, 0x31, 0x31, 0x33, 0x35, 0x31, 0x31, 0x31, 0x5a, 0x30,
|
||
+0x70, 0x31, 0x15, 0x30, 0x13, 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01,
|
||
+0x19, 0x16, 0x05, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x31, 0x12, 0x30, 0x10, 0x06, 0x0a, 0x09, 0x92,
|
||
+0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x02, 0x61, 0x64, 0x31, 0x0e, 0x30, 0x0c,
|
||
+0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x05, 0x55, 0x73, 0x65, 0x72, 0x73, 0x31, 0x0c, 0x30, 0x0a,
|
||
+0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x03, 0x74, 0x20, 0x75, 0x31, 0x25, 0x30, 0x23, 0x06, 0x09,
|
||
+0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x16, 0x74, 0x65, 0x73, 0x74, 0x2e,
|
||
+0x75, 0x73, 0x65, 0x72, 0x40, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x64, 0x6f, 0x6d, 0x61, 0x69,
|
||
+0x6e, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
|
||
+0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01,
|
||
+0x01, 0x00, 0x9c, 0xcf, 0x36, 0x99, 0xde, 0x63, 0x74, 0x2b, 0x77, 0x25, 0x9e, 0x24, 0xd9, 0x77,
|
||
+0x4b, 0x5f, 0x98, 0xc0, 0x8c, 0xd7, 0x20, 0x91, 0xc0, 0x1c, 0xe8, 0x37, 0x45, 0xbf, 0x3c, 0xd9,
|
||
+0x33, 0xbd, 0xe9, 0xde, 0xc9, 0x5d, 0xd4, 0xcd, 0x06, 0x0a, 0x0d, 0xd4, 0xf1, 0x7c, 0x74, 0x5b,
|
||
+0x29, 0xd5, 0x66, 0x9c, 0x2c, 0x9f, 0x6b, 0x1a, 0x0f, 0x0d, 0xe6, 0x6c, 0x62, 0xa5, 0x41, 0x4f,
|
||
+0xc3, 0xa4, 0x88, 0x27, 0x11, 0x5d, 0xb7, 0xb1, 0xfb, 0xf8, 0x8d, 0xee, 0x43, 0x8d, 0x93, 0xb5,
|
||
+0x8c, 0xb4, 0x34, 0x06, 0xf5, 0xe9, 0x2f, 0x5a, 0x26, 0x68, 0xd7, 0x43, 0x60, 0x82, 0x5e, 0x22,
|
||
+0xa7, 0xc6, 0x34, 0x40, 0x19, 0xa5, 0x8e, 0xf0, 0x58, 0x9f, 0x16, 0x2d, 0x43, 0x3f, 0x0c, 0xda,
|
||
+0xe2, 0x23, 0xf6, 0x09, 0x2a, 0x5e, 0xbd, 0x84, 0x27, 0xc8, 0xab, 0xd5, 0x70, 0xf8, 0x3d, 0x9c,
|
||
+0x14, 0xc2, 0xc2, 0xa2, 0x77, 0xe8, 0x44, 0x73, 0x10, 0x01, 0x34, 0x40, 0x1f, 0xc6, 0x2f, 0xa0,
|
||
+0x70, 0xee, 0x2f, 0xd5, 0x4b, 0xbe, 0x4c, 0xc7, 0x45, 0xf7, 0xac, 0x9c, 0xc3, 0x68, 0x5b, 0x1d,
|
||
+0x5a, 0x4b, 0x77, 0x65, 0x76, 0xe4, 0xb3, 0x92, 0xf4, 0x84, 0x0a, 0x9e, 0x6a, 0x9c, 0xc9, 0x53,
|
||
+0x42, 0x9f, 0x6d, 0xfe, 0xf9, 0xf5, 0xf2, 0x9a, 0x15, 0x50, 0x47, 0xef, 0xf4, 0x06, 0x59, 0xc8,
|
||
+0x50, 0x48, 0x4b, 0x46, 0x95, 0x68, 0x25, 0xc5, 0xbd, 0x4f, 0x65, 0x34, 0x00, 0xfc, 0x31, 0x69,
|
||
+0xf8, 0x3e, 0xe0, 0x20, 0x83, 0x41, 0x27, 0x0b, 0x5c, 0x46, 0x98, 0x14, 0xf0, 0x07, 0xde, 0x02,
|
||
+0x17, 0xb1, 0xd2, 0x9c, 0xbe, 0x1c, 0x0d, 0x56, 0x22, 0x1b, 0x02, 0xfe, 0xda, 0x69, 0xb9, 0xef,
|
||
+0x91, 0x37, 0x39, 0x7f, 0x24, 0xda, 0xc4, 0x81, 0x5e, 0x82, 0x31, 0x2f, 0x98, 0x1d, 0xf7, 0x73,
|
||
+0x5b, 0x23, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x03, 0x5d, 0x30, 0x82, 0x03, 0x59, 0x30,
|
||
+0x3d, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x15, 0x07, 0x04, 0x30, 0x30, 0x2e,
|
||
+0x06, 0x26, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x15, 0x08, 0x87, 0x85, 0xa1, 0x23, 0x84,
|
||
+0xc8, 0xb2, 0x26, 0x83, 0x9d, 0x9d, 0x21, 0x82, 0xd4, 0xa6, 0x1b, 0x86, 0xa3, 0xba, 0x37, 0x81,
|
||
+0x10, 0x85, 0x89, 0xd5, 0x02, 0xd6, 0x8f, 0x24, 0x02, 0x01, 0x64, 0x02, 0x01, 0x02, 0x30, 0x29,
|
||
+0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x22, 0x30, 0x20, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
|
||
+0x07, 0x03, 0x02, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x04, 0x06, 0x0a, 0x2b,
|
||
+0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x0a, 0x03, 0x04, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f,
|
||
+0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x35, 0x06, 0x09, 0x2b, 0x06, 0x01,
|
||
+0x04, 0x01, 0x82, 0x37, 0x15, 0x0a, 0x04, 0x28, 0x30, 0x26, 0x30, 0x0a, 0x06, 0x08, 0x2b, 0x06,
|
||
+0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x0a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
|
||
+0x03, 0x04, 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x0a, 0x03, 0x04,
|
||
+0x30, 0x81, 0x94, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x0f, 0x04, 0x81,
|
||
+0x86, 0x30, 0x81, 0x83, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01,
|
||
+0x2a, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2d, 0x30, 0x0b,
|
||
+0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x16, 0x30, 0x0b, 0x06, 0x09, 0x60,
|
||
+0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x19, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
|
||
+0x65, 0x03, 0x04, 0x01, 0x02, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04,
|
||
+0x01, 0x05, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x03, 0x07, 0x30, 0x07,
|
||
+0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x07, 0x30, 0x0e, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7,
|
||
+0x0d, 0x03, 0x02, 0x02, 0x02, 0x00, 0x80, 0x30, 0x0e, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7,
|
||
+0x0d, 0x03, 0x04, 0x02, 0x02, 0x02, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16,
|
||
+0x04, 0x14, 0x49, 0xac, 0xad, 0xe0, 0x65, 0x30, 0xc4, 0xce, 0xa0, 0x09, 0x03, 0x5b, 0xad, 0x4a,
|
||
+0x7b, 0x49, 0x5e, 0xc9, 0x6c, 0xb4, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30,
|
||
+0x16, 0x80, 0x14, 0x62, 0x50, 0xb6, 0x8d, 0xa1, 0xe6, 0x2d, 0x91, 0xbf, 0xb0, 0x54, 0x4d, 0x8f,
|
||
+0xa8, 0xca, 0x10, 0xae, 0xb8, 0xdd, 0x54, 0x30, 0x81, 0xcc, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04,
|
||
+0x81, 0xc4, 0x30, 0x81, 0xc1, 0x30, 0x81, 0xbe, 0xa0, 0x81, 0xbb, 0xa0, 0x81, 0xb8, 0x86, 0x81,
|
||
+0xb5, 0x6c, 0x64, 0x61, 0x70, 0x3a, 0x2f, 0x2f, 0x2f, 0x43, 0x4e, 0x3d, 0x61, 0x64, 0x2d, 0x41,
|
||
+0x44, 0x2d, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x2d, 0x43, 0x41, 0x2c, 0x43, 0x4e, 0x3d, 0x61,
|
||
+0x64, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2c, 0x43, 0x4e, 0x3d, 0x43, 0x44, 0x50, 0x2c,
|
||
+0x43, 0x4e, 0x3d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x25, 0x32, 0x30, 0x4b, 0x65, 0x79, 0x25,
|
||
+0x32, 0x30, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2c, 0x43, 0x4e, 0x3d, 0x53, 0x65,
|
||
+0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2c, 0x43, 0x4e, 0x3d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||
+0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x44, 0x43, 0x3d, 0x61, 0x64, 0x2c, 0x44, 0x43,
|
||
+0x3d, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x3f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
|
||
+0x74, 0x65, 0x52, 0x65, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74,
|
||
+0x3f, 0x62, 0x61, 0x73, 0x65, 0x3f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x43, 0x6c, 0x61, 0x73,
|
||
+0x73, 0x3d, 0x63, 0x52, 0x4c, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f,
|
||
+0x6e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x30, 0x81, 0xbe, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
|
||
+0x07, 0x01, 0x01, 0x04, 0x81, 0xb1, 0x30, 0x81, 0xae, 0x30, 0x81, 0xab, 0x06, 0x08, 0x2b, 0x06,
|
||
+0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x81, 0x9e, 0x6c, 0x64, 0x61, 0x70, 0x3a, 0x2f, 0x2f,
|
||
+0x2f, 0x43, 0x4e, 0x3d, 0x61, 0x64, 0x2d, 0x41, 0x44, 0x2d, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52,
|
||
+0x2d, 0x43, 0x41, 0x2c, 0x43, 0x4e, 0x3d, 0x41, 0x49, 0x41, 0x2c, 0x43, 0x4e, 0x3d, 0x50, 0x75,
|
||
+0x62, 0x6c, 0x69, 0x63, 0x25, 0x32, 0x30, 0x4b, 0x65, 0x79, 0x25, 0x32, 0x30, 0x53, 0x65, 0x72,
|
||
+0x76, 0x69, 0x63, 0x65, 0x73, 0x2c, 0x43, 0x4e, 0x3d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
|
||
+0x73, 0x2c, 0x43, 0x4e, 0x3d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69,
|
||
+0x6f, 0x6e, 0x2c, 0x44, 0x43, 0x3d, 0x61, 0x64, 0x2c, 0x44, 0x43, 0x3d, 0x64, 0x65, 0x76, 0x65,
|
||
+0x6c, 0x3f, 0x63, 0x41, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x3f,
|
||
+0x62, 0x61, 0x73, 0x65, 0x3f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x43, 0x6c, 0x61, 0x73, 0x73,
|
||
+0x3d, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x75,
|
||
+0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x3f, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x38,
|
||
+0x30, 0x36, 0xa0, 0x1c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x14, 0x02, 0x03,
|
||
+0xa0, 0x0e, 0x0c, 0x0c, 0x74, 0x75, 0x31, 0x40, 0x61, 0x64, 0x2e, 0x64, 0x65, 0x76, 0x65, 0x6c,
|
||
+0x81, 0x16, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x40, 0x65, 0x6d, 0x61, 0x69,
|
||
+0x6c, 0x2e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
|
||
+0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x41, 0x45, 0x0a, 0x6d,
|
||
+0xbb, 0x7f, 0x5c, 0x07, 0x0c, 0xc9, 0xb0, 0x39, 0x55, 0x6d, 0x7c, 0xb5, 0x02, 0xcd, 0xe8, 0xb2,
|
||
+0xe5, 0x02, 0x94, 0x77, 0x60, 0xdb, 0xd1, 0xaf, 0x1d, 0xdb, 0x44, 0x5f, 0xce, 0x83, 0xdb, 0x80,
|
||
+0x2e, 0xe2, 0xb2, 0x08, 0x25, 0x82, 0x14, 0xcb, 0x48, 0x95, 0x20, 0x13, 0x6c, 0xa9, 0xaa, 0xf8,
|
||
+0x31, 0x56, 0xed, 0xc0, 0x3b, 0xd4, 0xae, 0x2e, 0xe3, 0x8f, 0x05, 0xfc, 0xab, 0x5f, 0x2a, 0x69,
|
||
+0x23, 0xbc, 0xb8, 0x8c, 0xec, 0x2d, 0xa9, 0x0b, 0x86, 0x95, 0x73, 0x73, 0xdb, 0x17, 0xce, 0xc6,
|
||
+0xae, 0xc5, 0xb4, 0xc1, 0x25, 0x87, 0x3b, 0x67, 0x43, 0x9e, 0x87, 0x5a, 0xe6, 0xb9, 0xa0, 0x28,
|
||
+0x12, 0x3d, 0xa8, 0x2e, 0xd7, 0x5e, 0xef, 0x65, 0x2d, 0xe6, 0xa5, 0x67, 0x84, 0xac, 0xfd, 0x31,
|
||
+0xc1, 0x78, 0xd8, 0x72, 0x51, 0xa2, 0x88, 0x55, 0x0f, 0x97, 0x47, 0x93, 0x07, 0xea, 0x8a, 0x53,
|
||
+0x27, 0x4e, 0x34, 0x54, 0x34, 0x1f, 0xa0, 0x6a, 0x03, 0x44, 0xfb, 0x23, 0x61, 0x8e, 0x87, 0x8e,
|
||
+0x3c, 0xd0, 0x8f, 0xae, 0xe4, 0xcf, 0xee, 0x65, 0xa8, 0xba, 0x96, 0x68, 0x08, 0x1c, 0x60, 0xe2,
|
||
+0x4e, 0x11, 0xa3, 0x74, 0xb8, 0xa5, 0x4e, 0xea, 0x6a, 0x82, 0x4c, 0xc2, 0x4d, 0x63, 0x8e, 0x9f,
|
||
+0x7c, 0x2f, 0xa8, 0xc0, 0x62, 0xf8, 0xf7, 0xd9, 0x25, 0xc4, 0x91, 0xab, 0x4d, 0x6a, 0x44, 0xaf,
|
||
+0x75, 0x93, 0x53, 0x03, 0xa4, 0x99, 0xc8, 0xcd, 0x91, 0x89, 0x60, 0x75, 0x30, 0x99, 0x76, 0x05,
|
||
+0x5a, 0xa0, 0x03, 0xa7, 0xa1, 0x2c, 0x03, 0x04, 0x8f, 0xd4, 0x5a, 0x31, 0x52, 0x28, 0x5a, 0xe6,
|
||
+0xa2, 0xd3, 0x43, 0x21, 0x5b, 0xdc, 0xa2, 0x1d, 0x55, 0xa9, 0x48, 0xc5, 0xc4, 0xaa, 0xf3, 0x8b,
|
||
+0xe6, 0x3e, 0x75, 0x96, 0xe4, 0x3e, 0x64, 0xaf, 0xe8, 0xa7, 0x6a, 0xb6};
|
||
+
|
||
+void test_sss_cert_get_content(void **state)
|
||
+{
|
||
+ int ret;
|
||
+ struct sss_cert_content *content;
|
||
+
|
||
+ ret = sss_cert_get_content(NULL, test_cert_der, sizeof(test_cert_der),
|
||
+ &content);
|
||
+ assert_int_equal(ret , 0);
|
||
+ assert_non_null(content);
|
||
+ assert_non_null(content->issuer_str);
|
||
+ assert_string_equal(content->issuer_str, "CN=Certificate Authority,O=IPA.DEVEL");
|
||
+ assert_non_null(content->subject_str);
|
||
+ assert_string_equal(content->subject_str, "CN=ipa-devel.ipa.devel,O=IPA.DEVEL");
|
||
+ assert_int_equal(content->key_usage, SSS_KU_DIGITAL_SIGNATURE
|
||
+ |SSS_KU_NON_REPUDIATION
|
||
+ |SSS_KU_KEY_ENCIPHERMENT
|
||
+ |SSS_KU_DATA_ENCIPHERMENT);
|
||
+ assert_non_null(content->extended_key_usage_oids);
|
||
+ assert_non_null(content->extended_key_usage_oids[0]);
|
||
+ assert_true(string_in_list("1.3.6.1.5.5.7.3.1",
|
||
+ discard_const(content->extended_key_usage_oids), true));
|
||
+ assert_true(string_in_list("1.3.6.1.5.5.7.3.2",
|
||
+ discard_const(content->extended_key_usage_oids), true));
|
||
+ assert_null(content->extended_key_usage_oids[2]);
|
||
+ assert_int_equal(content->cert_der_size, sizeof(test_cert_der));
|
||
+ assert_memory_equal(content->cert_der, test_cert_der, sizeof(test_cert_der));
|
||
+
|
||
+ assert_non_null(content->issuer_rdn_list);
|
||
+ assert_string_equal(content->issuer_rdn_list[0], "O=IPA.DEVEL");
|
||
+ assert_string_equal(content->issuer_rdn_list[1], "CN=Certificate Authority");
|
||
+ assert_null(content->issuer_rdn_list[2]);
|
||
+
|
||
+ assert_non_null(content->subject_rdn_list);
|
||
+ assert_string_equal(content->subject_rdn_list[0], "O=IPA.DEVEL");
|
||
+ assert_string_equal(content->subject_rdn_list[1], "CN=ipa-devel.ipa.devel");
|
||
+ assert_null(content->subject_rdn_list[2]);
|
||
+
|
||
+
|
||
+ talloc_free(content);
|
||
+}
|
||
+
|
||
+void test_sss_cert_get_content_2(void **state)
|
||
+{
|
||
+ int ret;
|
||
+ struct sss_cert_content *content;
|
||
+ struct san_list *i;
|
||
+
|
||
+ ret = sss_cert_get_content(NULL, test_cert2_der, sizeof(test_cert2_der),
|
||
+ &content);
|
||
+ assert_int_equal(ret, 0);
|
||
+ assert_non_null(content);
|
||
+ assert_non_null(content->issuer_str);
|
||
+ assert_string_equal(content->issuer_str,
|
||
+ "CN=ad-AD-SERVER-CA,DC=ad,DC=devel");
|
||
+ assert_non_null(content->subject_str);
|
||
+#if 0
|
||
+FIXME:
|
||
+ assert_string_equal(content->subject_str,
|
||
+ "E=test.user@email.domain,CN=t u,CN=Users,DC=ad,DC=devel,DC=ad,DC=devel");
|
||
+ //"CN=t u/emailAddress=test.user@email.domain,DC=ad,DC=devel");
|
||
+#endif
|
||
+ assert_int_equal(content->key_usage, SSS_KU_DIGITAL_SIGNATURE
|
||
+ |SSS_KU_KEY_ENCIPHERMENT);
|
||
+ assert_non_null(content->extended_key_usage_oids);
|
||
+ assert_non_null(content->extended_key_usage_oids[0]);
|
||
+ assert_true(string_in_list("1.3.6.1.5.5.7.3.2",
|
||
+ discard_const(content->extended_key_usage_oids), true));
|
||
+ assert_true(string_in_list("1.3.6.1.5.5.7.3.4",
|
||
+ discard_const(content->extended_key_usage_oids), true));
|
||
+ /* Can use Microsoft Encrypted File System OID */
|
||
+ assert_true(string_in_list("1.3.6.1.4.1.311.10.3.4",
|
||
+ discard_const(content->extended_key_usage_oids), true));
|
||
+ assert_null(content->extended_key_usage_oids[3]);
|
||
+ assert_int_equal(content->cert_der_size, sizeof(test_cert2_der));
|
||
+ assert_memory_equal(content->cert_der, test_cert2_der,
|
||
+ sizeof(test_cert2_der));
|
||
+
|
||
+ assert_non_null(content->issuer_rdn_list);
|
||
+ assert_string_equal(content->issuer_rdn_list[0], "DC=devel");
|
||
+ assert_string_equal(content->issuer_rdn_list[1], "DC=ad");
|
||
+ assert_string_equal(content->issuer_rdn_list[2], "CN=ad-AD-SERVER-CA");
|
||
+ assert_null(content->issuer_rdn_list[3]);
|
||
+
|
||
+ assert_non_null(content->subject_rdn_list);
|
||
+ assert_string_equal(content->subject_rdn_list[0], "DC=devel");
|
||
+ assert_string_equal(content->subject_rdn_list[1], "DC=ad");
|
||
+ assert_string_equal(content->subject_rdn_list[2], "CN=Users");
|
||
+ assert_string_equal(content->subject_rdn_list[3], "CN=t u");
|
||
+ assert_string_equal(content->subject_rdn_list[4],
|
||
+ "E=test.user@email.domain");
|
||
+ //"CN=t u/emailAddress=test.user@email.domain");
|
||
+ assert_null(content->subject_rdn_list[5]);
|
||
+
|
||
+ assert_non_null(content->san_list);
|
||
+
|
||
+ DLIST_FOR_EACH(i, content->san_list) {
|
||
+ switch (i->san_opt) {
|
||
+ case SAN_RFC822_NAME:
|
||
+ assert_string_equal(i->val, "test.user@email.domain");
|
||
+ assert_string_equal(i->short_name, "test.user");
|
||
+ break;
|
||
+ case SAN_STRING_OTHER_NAME:
|
||
+ assert_string_equal(i->other_name_oid, "1.3.6.1.4.1.311.20.2.3");
|
||
+ assert_int_equal(i->bin_val_len, 14);
|
||
+ assert_memory_equal(i->bin_val, "\f\ftu1@ad.devel", 14);
|
||
+ break;
|
||
+ case SAN_NT:
|
||
+ case SAN_PRINCIPAL:
|
||
+ assert_string_equal(i->val, "tu1@ad.devel");
|
||
+ assert_string_equal(i->short_name, "tu1");
|
||
+ break;
|
||
+ default:
|
||
+ assert_true(false);
|
||
+ }
|
||
+ }
|
||
+
|
||
+ talloc_free(content);
|
||
+}
|
||
+
|
||
+static void test_sss_certmap_match_cert(void **state)
|
||
+{
|
||
+ struct sss_certmap_ctx *ctx;
|
||
+ int ret;
|
||
+ size_t c;
|
||
+
|
||
+ struct match_tests {
|
||
+ const char *rule;
|
||
+ int result;
|
||
+ } match_tests[] = {
|
||
+ {"KRB5:<KU>digitalSignature", 0},
|
||
+ {"KRB5:<KU>digitalSignature,nonRepudiation", 0},
|
||
+ {"KRB5:<KU>digitalSignature,cRLSign", ENOENT},
|
||
+ {"KRB5:<EKU>clientAuth", 0},
|
||
+ {"KRB5:<EKU>clientAuth,OCSPSigning", ENOENT},
|
||
+ {"KRB5:<EKU>clientAuth,serverAuth", 0},
|
||
+ {NULL, 0}
|
||
+ };
|
||
+
|
||
+ struct match_tests match_tests_2[] = {
|
||
+ {"KRB5:<KU>digitalSignature", 0},
|
||
+ {"KRB5:<KU>keyEncipherment", 0},
|
||
+ {"KRB5:<KU>digitalSignature,keyEncipherment", 0},
|
||
+ {"KRB5:<KU>digitalSignature,keyEncipherment,cRLSign", ENOENT},
|
||
+ {"KRB5:<EKU>clientAuth", 0},
|
||
+ {"KRB5:<EKU>clientAuth,1.3.6.1.4.1.311.10.3.4", 0},
|
||
+ {"KRB5:<EKU>clientAuth,1.3.6.1.4.1.311.10.3.41", ENOENT},
|
||
+ {"KRB5:<SAN>tu1", 0},
|
||
+ {"KRB5:<SAN:Principal>tu1", 0},
|
||
+ {"KRB5:<SAN:ntPrincipalName>tu1", 0},
|
||
+ {"KRB5:<SAN:pkinitSAN>tu1", ENOENT},
|
||
+ {"KRB5:<SAN:Principal>^tu1@ad.devel$", 0},
|
||
+ {"KRB5:<SAN:rfc822Name>tu", ENOENT},
|
||
+ {"KRB5:<SAN:rfc822Name>test.user", 0},
|
||
+ {"KRB5:<SAN:rfc822Name>test.user<SAN>tu1", 0},
|
||
+ {"KRB5:||<SAN:rfc822Name>test.user<SAN>tu1", 0},
|
||
+ {"KRB5:&&<SAN:rfc822Name>tu1<SAN>tu1", ENOENT},
|
||
+ {"KRB5:||<SAN:rfc822Name>tu1<SAN>tu1", 0},
|
||
+ {"KRB5:<SAN:otherName>MTIz", ENOENT}, /* 123 */
|
||
+ {"KRB5:<SAN:otherName>DAx0dTFAYWQuZGV2ZWw=", 0}, /* "\f\ftu1@ad.devel" */
|
||
+ {"KRB5:<SAN:otherName>DAx0dTFAYWQuZGV2ZWx4", ENOENT}, /* "\f\ftu1@ad.develx" */
|
||
+ {"KRB5:<SAN:otherName>dHUxQGFkLmRldmVs", 0}, /* "tu1@ad.devel" */
|
||
+ {"KRB5:<SAN:1.3.6.1.4.1.311.20.2.3>test", ENOENT},
|
||
+ {"KRB5:<SAN:1.3.6.1.4.1.311.20.2.3>tu1@ad", 0},
|
||
+ /* Fails becasue the NT principal SAN starts with binary values */
|
||
+ {"KRB5:<SAN:1.3.6.1.4.1.311.20.2.3>^tu1@ad.devel$", ENOENT},
|
||
+ {NULL, 0}
|
||
+ };
|
||
+
|
||
+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx);
|
||
+ assert_int_equal(ret, EOK);
|
||
+ assert_non_null(ctx);
|
||
+ assert_null(ctx->prio_list);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 1, "KRB5:<ISSUER>xyz<SUBJECT>xyz",
|
||
+ NULL, NULL);
|
||
+ assert_int_equal(ret, EOK);
|
||
+
|
||
+ ret = sss_certmap_match_cert(ctx, discard_const(test_cert_der),
|
||
+ sizeof(test_cert_der));
|
||
+ assert_int_equal(ret, ENOENT);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 1,
|
||
+ "KRB5:<ISSUER>CN=Certificate Authority,O=IPA.DEVEL",
|
||
+ NULL, NULL);
|
||
+ assert_int_equal(ret, EOK);
|
||
+
|
||
+ ret = sss_certmap_match_cert(ctx, discard_const(test_cert_der),
|
||
+ sizeof(test_cert_der));
|
||
+ assert_int_equal(ret, 0);
|
||
+
|
||
+ sss_certmap_free_ctx(ctx);
|
||
+
|
||
+ for (c = 0; match_tests[c].rule != NULL; c++) {
|
||
+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx);
|
||
+ assert_int_equal(ret, EOK);
|
||
+ assert_non_null(ctx);
|
||
+ assert_null(ctx->prio_list);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 1, match_tests[c].rule, NULL, NULL);
|
||
+ assert_int_equal(ret, EOK);
|
||
+
|
||
+ ret = sss_certmap_match_cert(ctx, discard_const(test_cert_der),
|
||
+ sizeof(test_cert_der));
|
||
+ assert_int_equal(ret, match_tests[c].result);
|
||
+
|
||
+ sss_certmap_free_ctx(ctx);
|
||
+ }
|
||
+
|
||
+ for (c = 0; match_tests_2[c].rule != NULL; c++) {
|
||
+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx);
|
||
+ assert_int_equal(ret, EOK);
|
||
+ assert_non_null(ctx);
|
||
+ assert_null(ctx->prio_list);
|
||
+
|
||
+ print_error("Checking matching rule [%s]\n", match_tests_2[c].rule);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 1, match_tests_2[c].rule, NULL, NULL);
|
||
+ assert_int_equal(ret, EOK);
|
||
+
|
||
+ ret = sss_certmap_match_cert(ctx, discard_const(test_cert2_der),
|
||
+ sizeof(test_cert2_der));
|
||
+ assert_int_equal(ret, match_tests_2[c].result);
|
||
+
|
||
+ sss_certmap_free_ctx(ctx);
|
||
+ }
|
||
+}
|
||
+
|
||
+static void test_sss_certmap_add_mapping_rule(void **state)
|
||
+{
|
||
+ struct sss_certmap_ctx *ctx;
|
||
+ int ret;
|
||
+
|
||
+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx);
|
||
+ assert_int_equal(ret, EOK);
|
||
+ assert_non_null(ctx);
|
||
+ assert_null(ctx->prio_list);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 1, NULL, "FWEAWEF:fwefwe", NULL);
|
||
+ assert_int_equal(ret, ESRCH);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 1, NULL, "LDAP:abc", NULL);
|
||
+ assert_int_equal(ret, 0);
|
||
+ assert_non_null(ctx->prio_list);
|
||
+ assert_non_null(ctx->prio_list->rule_list);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_mapping_rule);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_mapping_rule->list);
|
||
+ assert_int_equal(comp_string,
|
||
+ ctx->prio_list->rule_list->parsed_mapping_rule->list->type);
|
||
+ assert_string_equal("abc",
|
||
+ ctx->prio_list->rule_list->parsed_mapping_rule->list->val);
|
||
+ talloc_free(ctx);
|
||
+
|
||
+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx);
|
||
+ assert_int_equal(ret, EOK);
|
||
+ assert_non_null(ctx);
|
||
+ assert_null(ctx->prio_list);
|
||
+ ret = sss_certmap_add_rule(ctx, 1, NULL, "LDAP:abc{issuer_dn}", NULL);
|
||
+ assert_int_equal(ret, 0);
|
||
+ assert_non_null(ctx->prio_list);
|
||
+ assert_non_null(ctx->prio_list->rule_list);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_mapping_rule);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_mapping_rule->list);
|
||
+ assert_int_equal(comp_string,
|
||
+ ctx->prio_list->rule_list->parsed_mapping_rule->list->type);
|
||
+ assert_string_equal("abc",
|
||
+ ctx->prio_list->rule_list->parsed_mapping_rule->list->val);
|
||
+ assert_int_equal(comp_template,
|
||
+ ctx->prio_list->rule_list->parsed_mapping_rule->list->next->type);
|
||
+ assert_string_equal("issuer_dn",
|
||
+ ctx->prio_list->rule_list->parsed_mapping_rule->list->next->val);
|
||
+ talloc_free(ctx);
|
||
+
|
||
+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx);
|
||
+ assert_int_equal(ret, EOK);
|
||
+ assert_non_null(ctx);
|
||
+ assert_null(ctx->prio_list);
|
||
+ ret = sss_certmap_add_rule(ctx, 1, NULL, "{issuer_dn}a:b{{c}}", NULL);
|
||
+ assert_int_equal(ret, 0);
|
||
+ assert_non_null(ctx->prio_list);
|
||
+ assert_non_null(ctx->prio_list->rule_list);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_mapping_rule);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_mapping_rule->list);
|
||
+ assert_int_equal(comp_template,
|
||
+ ctx->prio_list->rule_list->parsed_mapping_rule->list->type);
|
||
+ assert_string_equal("issuer_dn",
|
||
+ ctx->prio_list->rule_list->parsed_mapping_rule->list->val);
|
||
+ assert_int_equal(comp_string,
|
||
+ ctx->prio_list->rule_list->parsed_mapping_rule->list->next->type);
|
||
+ assert_string_equal("a:b{c}",
|
||
+ ctx->prio_list->rule_list->parsed_mapping_rule->list->next->val);
|
||
+ talloc_free(ctx);
|
||
+
|
||
+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx);
|
||
+ assert_int_equal(ret, EOK);
|
||
+ assert_non_null(ctx);
|
||
+ assert_null(ctx->prio_list);
|
||
+ ret = sss_certmap_add_rule(ctx, 1, NULL, "LDAP:{issuer_dn}{subject_dn}",
|
||
+ NULL);
|
||
+ assert_int_equal(ret, 0);
|
||
+ assert_non_null(ctx->prio_list);
|
||
+ assert_non_null(ctx->prio_list->rule_list);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_mapping_rule);
|
||
+ assert_non_null(ctx->prio_list->rule_list->parsed_mapping_rule->list);
|
||
+ assert_int_equal(comp_template,
|
||
+ ctx->prio_list->rule_list->parsed_mapping_rule->list->type);
|
||
+ assert_string_equal("issuer_dn",
|
||
+ ctx->prio_list->rule_list->parsed_mapping_rule->list->val);
|
||
+ assert_int_equal(comp_template,
|
||
+ ctx->prio_list->rule_list->parsed_mapping_rule->list->next->type);
|
||
+ assert_string_equal("subject_dn",
|
||
+ ctx->prio_list->rule_list->parsed_mapping_rule->list->next->val);
|
||
+ talloc_free(ctx);
|
||
+}
|
||
+
|
||
+#define TEST_CERT_BIN \
|
||
+ "\\30\\82\\04\\09\\30\\82\\02\\f1\\a0\\03\\02\\01\\02\\02\\01\\09" \
|
||
+ "\\30\\0d\\06\\09\\2a\\86\\48\\86\\f7\\0d\\01\\01\\0b\\05\\00\\30" \
|
||
+ "\\34\\31\\12\\30\\10\\06\\03\\55\\04\\0a\\0c\\09\\49\\50\\41\\2e" \
|
||
+ "\\44\\45\\56\\45\\4c\\31\\1e\\30\\1c\\06\\03\\55\\04\\03\\0c\\15" \
|
||
+ "\\43\\65\\72\\74\\69\\66\\69\\63\\61\\74\\65\\20\\41\\75\\74\\68" \
|
||
+ "\\6f\\72\\69\\74\\79\\30\\1e\\17\\0d\\31\\35\\30\\34\\32\\38\\31" \
|
||
+ "\\30\\32\\31\\31\\31\\5a\\17\\0d\\31\\37\\30\\34\\32\\38\\31\\30" \
|
||
+ "\\32\\31\\31\\31\\5a\\30\\32\\31\\12\\30\\10\\06\\03\\55\\04\\0a" \
|
||
+ "\\0c\\09\\49\\50\\41\\2e\\44\\45\\56\\45\\4c\\31\\1c\\30\\1a\\06" \
|
||
+ "\\03\\55\\04\\03\\0c\\13\\69\\70\\61\\2d\\64\\65\\76\\65\\6c\\2e" \
|
||
+ "\\69\\70\\61\\2e\\64\\65\\76\\65\\6c\\30\\82\\01\\22\\30\\0d\\06" \
|
||
+ "\\09\\2a\\86\\48\\86\\f7\\0d\\01\\01\\01\\05\\00\\03\\82\\01\\0f" \
|
||
+ "\\00\\30\\82\\01\\0a\\02\\82\\01\\01\\00\\b2\\32\\92\\ab\\47\\b8" \
|
||
+ "\\0c\\13\\54\\4a\\1f\\1e\\29\\06\\ff\\d0\\50\\cb\\f7\\5f\\79\\91" \
|
||
+ "\\65\\b1\\39\\01\\83\\6a\\ad\\9e\\77\\3b\\f3\\0d\\d7\\b9\\f6\\dc" \
|
||
+ "\\9e\\4a\\49\\a7\\d0\\66\\72\\cc\\bf\\77\\d6\\de\\a9\\fe\\67\\96" \
|
||
+ "\\cc\\49\\f1\\37\\23\\2e\\c4\\50\\f4\\eb\\ba\\62\\d4\\23\\4d\\f3" \
|
||
+ "\\37\\38\\82\\ee\\3b\\3f\\2c\\d0\\80\\9b\\17\\aa\\9b\\eb\\a6\\dd" \
|
||
+ "\\f6\\15\\ff\\06\\b2\\ce\\ff\\df\\8a\\9e\\95\\85\\49\\1f\\84\\fd" \
|
||
+ "\\81\\26\\ce\\06\\32\\0d\\36\\ca\\7c\\15\\81\\68\\6b\\8f\\3e\\b3" \
|
||
+ "\\a2\\fc\\ae\\af\\c2\\44\\58\\15\\95\\40\\fc\\56\\19\\91\\80\\ed" \
|
||
+ "\\42\\11\\66\\04\\ef\\3c\\e0\\76\\33\\4b\\83\\fa\\7e\\b4\\47\\dc" \
|
||
+ "\\fb\\ed\\46\\a5\\8d\\0a\\66\\87\\a5\\ef\\7b\\74\\62\\ac\\be\\73" \
|
||
+ "\\36\\c9\\b4\\fe\\20\\c4\\81\\f3\\fe\\78\\19\\a8\\d0\\af\\7f\\81" \
|
||
+ "\\72\\24\\61\\d9\\76\\93\\e3\\0b\\d2\\4f\\19\\17\\33\\57\\d4\\82" \
|
||
+ "\\b0\\f1\\a8\\03\\f6\\01\\99\\a9\\b8\\8c\\83\\c9\\ba\\19\\87\\ea" \
|
||
+ "\\d6\\3b\\06\\eb\\4c\\f7\\f1\\e5\\28\\a9\\10\\b6\\46\\de\\e1\\e1" \
|
||
+ "\\3f\\c1\\cc\\72\\be\\2a\\43\\c6\\f6\\d0\\b5\\a0\\c4\\24\\6e\\4f" \
|
||
+ "\\bd\\ec\\22\\8a\\07\\11\\3d\\f9\\d3\\15\\02\\03\\01\\00\\01\\a3" \
|
||
+ "\\82\\01\\26\\30\\82\\01\\22\\30\\1f\\06\\03\\55\\1d\\23\\04\\18" \
|
||
+ "\\30\\16\\80\\14\\f2\\9d\\42\\4e\\0f\\c4\\48\\25\\58\\2f\\1c\\ce" \
|
||
+ "\\0f\\a1\\3f\\22\\c8\\55\\c8\\91\\30\\3b\\06\\08\\2b\\06\\01\\05" \
|
||
+ "\\05\\07\\01\\01\\04\\2f\\30\\2d\\30\\2b\\06\\08\\2b\\06\\01\\05" \
|
||
+ "\\05\\07\\30\\01\\86\\1f\\68\\74\\74\\70\\3a\\2f\\2f\\69\\70\\61" \
|
||
+ "\\2d\\63\\61\\2e\\69\\70\\61\\2e\\64\\65\\76\\65\\6c\\2f\\63\\61" \
|
||
+ "\\2f\\6f\\63\\73\\70\\30\\0e\\06\\03\\55\\1d\\0f\\01\\01\\ff\\04" \
|
||
+ "\\04\\03\\02\\04\\f0\\30\\1d\\06\\03\\55\\1d\\25\\04\\16\\30\\14" \
|
||
+ "\\06\\08\\2b\\06\\01\\05\\05\\07\\03\\01\\06\\08\\2b\\06\\01\\05" \
|
||
+ "\\05\\07\\03\\02\\30\\74\\06\\03\\55\\1d\\1f\\04\\6d\\30\\6b\\30" \
|
||
+ "\\69\\a0\\31\\a0\\2f\\86\\2d\\68\\74\\74\\70\\3a\\2f\\2f\\69\\70" \
|
||
+ "\\61\\2d\\63\\61\\2e\\69\\70\\61\\2e\\64\\65\\76\\65\\6c\\2f\\69" \
|
||
+ "\\70\\61\\2f\\63\\72\\6c\\2f\\4d\\61\\73\\74\\65\\72\\43\\52\\4c" \
|
||
+ "\\2e\\62\\69\\6e\\a2\\34\\a4\\32\\30\\30\\31\\0e\\30\\0c\\06\\03" \
|
||
+ "\\55\\04\\0a\\0c\\05\\69\\70\\61\\63\\61\\31\\1e\\30\\1c\\06\\03" \
|
||
+ "\\55\\04\\03\\0c\\15\\43\\65\\72\\74\\69\\66\\69\\63\\61\\74\\65" \
|
||
+ "\\20\\41\\75\\74\\68\\6f\\72\\69\\74\\79\\30\\1d\\06\\03\\55\\1d" \
|
||
+ "\\0e\\04\\16\\04\\14\\2d\\2b\\3f\\cb\\f5\\b2\\ff\\32\\2c\\a8\\c2" \
|
||
+ "\\1c\\dd\\bd\\8c\\80\\1e\\dd\\31\\82\\30\\0d\\06\\09\\2a\\86\\48" \
|
||
+ "\\86\\f7\\0d\\01\\01\\0b\\05\\00\\03\\82\\01\\01\\00\\9a\\47\\2e" \
|
||
+ "\\50\\a7\\4d\\1d\\53\\0f\\c9\\71\\42\\0c\\e5\\da\\7d\\49\\64\\e7" \
|
||
+ "\\ab\\c8\\df\\df\\02\\c1\\87\\d1\\5b\\de\\da\\6f\\2b\\e4\\f0\\be" \
|
||
+ "\\ba\\09\\df\\02\\85\\0b\\8a\\e6\\9b\\06\\7d\\69\\38\\6c\\72\\ff" \
|
||
+ "\\4c\\7b\\2a\\0d\\3f\\23\\2f\\16\\46\\ff\\05\\93\\b0\\ea\\24\\28" \
|
||
+ "\\d7\\12\\a1\\57\\b8\\59\\19\\25\\f3\\43\\0a\\d3\\fd\\0f\\37\\8d" \
|
||
+ "\\b8\\ca\\15\\e7\\48\\8a\\a0\\c7\\c7\\4b\\7f\\01\\3c\\58\\d7\\37" \
|
||
+ "\\e5\\ff\\7d\\2b\\01\\ac\\0d\\9f\\51\\6a\\e5\\40\\24\\e6\\5e\\55" \
|
||
+ "\\0d\\f7\\b8\\2f\\42\\ac\\6d\\e5\\29\\6b\\c6\\0b\\a4\\bf\\19\\bd" \
|
||
+ "\\39\\27\\ee\\fe\\c5\\b3\\db\\62\\d4\\be\\d2\\47\\ba\\96\\30\\5a" \
|
||
+ "\\fd\\62\\00\\b8\\27\\5d\\2f\\3a\\94\\0b\\95\\35\\85\\40\\2c\\bc" \
|
||
+ "\\67\\df\\8a\\f9\\f1\\7b\\19\\96\\3e\\42\\48\\13\\23\\04\\95\\a9" \
|
||
+ "\\6b\\11\\33\\81\\47\\5a\\83\\72\\f6\\20\\fa\\8e\\41\\7b\\8f\\77" \
|
||
+ "\\47\\7c\\c7\\5d\\46\\f4\\4f\\fd\\81\\0a\\ae\\39\\27\\b6\\6a\\26" \
|
||
+ "\\63\\b1\\d3\\bf\\55\\83\\82\\9b\\36\\6c\\33\\64\\0f\\50\\c0\\55" \
|
||
+ "\\94\\13\\c3\\85\\f4\\d5\\71\\65\\d0\\c0\\dd\\fc\\e6\\ec\\9c\\5b" \
|
||
+ "\\f0\\11\\b5\\2c\\f3\\48\\c1\\36\\8c\\a2\\96\\48\\84"
|
||
+
|
||
+#define TEST_CERT2_BIN \
|
||
+ "\\30\\82\\06\\98\\30\\82\\05\\80\\a0\\03\\02\\01\\02\\02\\0a\\61" \
|
||
+ "\\22\\88\\c2\\00\\00\\00\\00\\02\\a6\\30\\0d\\06\\09\\2a\\86\\48" \
|
||
+ "\\86\\f7\\0d\\01\\01\\05\\05\\00\\30\\45\\31\\15\\30\\13\\06\\0a" \
|
||
+ "\\09\\92\\26\\89\\93\\f2\\2c\\64\\01\\19\\16\\05\\64\\65\\76\\65" \
|
||
+ "\\6c\\31\\12\\30\\10\\06\\0a\\09\\92\\26\\89\\93\\f2\\2c\\64\\01" \
|
||
+ "\\19\\16\\02\\61\\64\\31\\18\\30\\16\\06\\03\\55\\04\\03\\13\\0f" \
|
||
+ "\\61\\64\\2d\\41\\44\\2d\\53\\45\\52\\56\\45\\52\\2d\\43\\41\\30" \
|
||
+ "\\1e\\17\\0d\\31\\36\\31\\31\\31\\31\\31\\33\\35\\31\\31\\31\\5a" \
|
||
+ "\\17\\0d\\31\\37\\31\\31\\31\\31\\31\\33\\35\\31\\31\\31\\5a\\30" \
|
||
+ "\\70\\31\\15\\30\\13\\06\\0a\\09\\92\\26\\89\\93\\f2\\2c\\64\\01" \
|
||
+ "\\19\\16\\05\\64\\65\\76\\65\\6c\\31\\12\\30\\10\\06\\0a\\09\\92" \
|
||
+ "\\26\\89\\93\\f2\\2c\\64\\01\\19\\16\\02\\61\\64\\31\\0e\\30\\0c" \
|
||
+ "\\06\\03\\55\\04\\03\\13\\05\\55\\73\\65\\72\\73\\31\\0c\\30\\0a" \
|
||
+ "\\06\\03\\55\\04\\03\\13\\03\\74\\20\\75\\31\\25\\30\\23\\06\\09" \
|
||
+ "\\2a\\86\\48\\86\\f7\\0d\\01\\09\\01\\16\\16\\74\\65\\73\\74\\2e" \
|
||
+ "\\75\\73\\65\\72\\40\\65\\6d\\61\\69\\6c\\2e\\64\\6f\\6d\\61\\69" \
|
||
+ "\\6e\\30\\82\\01\\22\\30\\0d\\06\\09\\2a\\86\\48\\86\\f7\\0d\\01" \
|
||
+ "\\01\\01\\05\\00\\03\\82\\01\\0f\\00\\30\\82\\01\\0a\\02\\82\\01" \
|
||
+ "\\01\\00\\9c\\cf\\36\\99\\de\\63\\74\\2b\\77\\25\\9e\\24\\d9\\77" \
|
||
+ "\\4b\\5f\\98\\c0\\8c\\d7\\20\\91\\c0\\1c\\e8\\37\\45\\bf\\3c\\d9" \
|
||
+ "\\33\\bd\\e9\\de\\c9\\5d\\d4\\cd\\06\\0a\\0d\\d4\\f1\\7c\\74\\5b" \
|
||
+ "\\29\\d5\\66\\9c\\2c\\9f\\6b\\1a\\0f\\0d\\e6\\6c\\62\\a5\\41\\4f" \
|
||
+ "\\c3\\a4\\88\\27\\11\\5d\\b7\\b1\\fb\\f8\\8d\\ee\\43\\8d\\93\\b5" \
|
||
+ "\\8c\\b4\\34\\06\\f5\\e9\\2f\\5a\\26\\68\\d7\\43\\60\\82\\5e\\22" \
|
||
+ "\\a7\\c6\\34\\40\\19\\a5\\8e\\f0\\58\\9f\\16\\2d\\43\\3f\\0c\\da" \
|
||
+ "\\e2\\23\\f6\\09\\2a\\5e\\bd\\84\\27\\c8\\ab\\d5\\70\\f8\\3d\\9c" \
|
||
+ "\\14\\c2\\c2\\a2\\77\\e8\\44\\73\\10\\01\\34\\40\\1f\\c6\\2f\\a0" \
|
||
+ "\\70\\ee\\2f\\d5\\4b\\be\\4c\\c7\\45\\f7\\ac\\9c\\c3\\68\\5b\\1d" \
|
||
+ "\\5a\\4b\\77\\65\\76\\e4\\b3\\92\\f4\\84\\0a\\9e\\6a\\9c\\c9\\53" \
|
||
+ "\\42\\9f\\6d\\fe\\f9\\f5\\f2\\9a\\15\\50\\47\\ef\\f4\\06\\59\\c8" \
|
||
+ "\\50\\48\\4b\\46\\95\\68\\25\\c5\\bd\\4f\\65\\34\\00\\fc\\31\\69" \
|
||
+ "\\f8\\3e\\e0\\20\\83\\41\\27\\0b\\5c\\46\\98\\14\\f0\\07\\de\\02" \
|
||
+ "\\17\\b1\\d2\\9c\\be\\1c\\0d\\56\\22\\1b\\02\\fe\\da\\69\\b9\\ef" \
|
||
+ "\\91\\37\\39\\7f\\24\\da\\c4\\81\\5e\\82\\31\\2f\\98\\1d\\f7\\73" \
|
||
+ "\\5b\\23\\02\\03\\01\\00\\01\\a3\\82\\03\\5d\\30\\82\\03\\59\\30" \
|
||
+ "\\3d\\06\\09\\2b\\06\\01\\04\\01\\82\\37\\15\\07\\04\\30\\30\\2e" \
|
||
+ "\\06\\26\\2b\\06\\01\\04\\01\\82\\37\\15\\08\\87\\85\\a1\\23\\84" \
|
||
+ "\\c8\\b2\\26\\83\\9d\\9d\\21\\82\\d4\\a6\\1b\\86\\a3\\ba\\37\\81" \
|
||
+ "\\10\\85\\89\\d5\\02\\d6\\8f\\24\\02\\01\\64\\02\\01\\02\\30\\29" \
|
||
+ "\\06\\03\\55\\1d\\25\\04\\22\\30\\20\\06\\08\\2b\\06\\01\\05\\05" \
|
||
+ "\\07\\03\\02\\06\\08\\2b\\06\\01\\05\\05\\07\\03\\04\\06\\0a\\2b" \
|
||
+ "\\06\\01\\04\\01\\82\\37\\0a\\03\\04\\30\\0e\\06\\03\\55\\1d\\0f" \
|
||
+ "\\01\\01\\ff\\04\\04\\03\\02\\05\\a0\\30\\35\\06\\09\\2b\\06\\01" \
|
||
+ "\\04\\01\\82\\37\\15\\0a\\04\\28\\30\\26\\30\\0a\\06\\08\\2b\\06" \
|
||
+ "\\01\\05\\05\\07\\03\\02\\30\\0a\\06\\08\\2b\\06\\01\\05\\05\\07" \
|
||
+ "\\03\\04\\30\\0c\\06\\0a\\2b\\06\\01\\04\\01\\82\\37\\0a\\03\\04" \
|
||
+ "\\30\\81\\94\\06\\09\\2a\\86\\48\\86\\f7\\0d\\01\\09\\0f\\04\\81" \
|
||
+ "\\86\\30\\81\\83\\30\\0b\\06\\09\\60\\86\\48\\01\\65\\03\\04\\01" \
|
||
+ "\\2a\\30\\0b\\06\\09\\60\\86\\48\\01\\65\\03\\04\\01\\2d\\30\\0b" \
|
||
+ "\\06\\09\\60\\86\\48\\01\\65\\03\\04\\01\\16\\30\\0b\\06\\09\\60" \
|
||
+ "\\86\\48\\01\\65\\03\\04\\01\\19\\30\\0b\\06\\09\\60\\86\\48\\01" \
|
||
+ "\\65\\03\\04\\01\\02\\30\\0b\\06\\09\\60\\86\\48\\01\\65\\03\\04" \
|
||
+ "\\01\\05\\30\\0a\\06\\08\\2a\\86\\48\\86\\f7\\0d\\03\\07\\30\\07" \
|
||
+ "\\06\\05\\2b\\0e\\03\\02\\07\\30\\0e\\06\\08\\2a\\86\\48\\86\\f7" \
|
||
+ "\\0d\\03\\02\\02\\02\\00\\80\\30\\0e\\06\\08\\2a\\86\\48\\86\\f7" \
|
||
+ "\\0d\\03\\04\\02\\02\\02\\00\\30\\1d\\06\\03\\55\\1d\\0e\\04\\16" \
|
||
+ "\\04\\14\\49\\ac\\ad\\e0\\65\\30\\c4\\ce\\a0\\09\\03\\5b\\ad\\4a" \
|
||
+ "\\7b\\49\\5e\\c9\\6c\\b4\\30\\1f\\06\\03\\55\\1d\\23\\04\\18\\30" \
|
||
+ "\\16\\80\\14\\62\\50\\b6\\8d\\a1\\e6\\2d\\91\\bf\\b0\\54\\4d\\8f" \
|
||
+ "\\a8\\ca\\10\\ae\\b8\\dd\\54\\30\\81\\cc\\06\\03\\55\\1d\\1f\\04" \
|
||
+ "\\81\\c4\\30\\81\\c1\\30\\81\\be\\a0\\81\\bb\\a0\\81\\b8\\86\\81" \
|
||
+ "\\b5\\6c\\64\\61\\70\\3a\\2f\\2f\\2f\\43\\4e\\3d\\61\\64\\2d\\41" \
|
||
+ "\\44\\2d\\53\\45\\52\\56\\45\\52\\2d\\43\\41\\2c\\43\\4e\\3d\\61" \
|
||
+ "\\64\\2d\\73\\65\\72\\76\\65\\72\\2c\\43\\4e\\3d\\43\\44\\50\\2c" \
|
||
+ "\\43\\4e\\3d\\50\\75\\62\\6c\\69\\63\\25\\32\\30\\4b\\65\\79\\25" \
|
||
+ "\\32\\30\\53\\65\\72\\76\\69\\63\\65\\73\\2c\\43\\4e\\3d\\53\\65" \
|
||
+ "\\72\\76\\69\\63\\65\\73\\2c\\43\\4e\\3d\\43\\6f\\6e\\66\\69\\67" \
|
||
+ "\\75\\72\\61\\74\\69\\6f\\6e\\2c\\44\\43\\3d\\61\\64\\2c\\44\\43" \
|
||
+ "\\3d\\64\\65\\76\\65\\6c\\3f\\63\\65\\72\\74\\69\\66\\69\\63\\61" \
|
||
+ "\\74\\65\\52\\65\\76\\6f\\63\\61\\74\\69\\6f\\6e\\4c\\69\\73\\74" \
|
||
+ "\\3f\\62\\61\\73\\65\\3f\\6f\\62\\6a\\65\\63\\74\\43\\6c\\61\\73" \
|
||
+ "\\73\\3d\\63\\52\\4c\\44\\69\\73\\74\\72\\69\\62\\75\\74\\69\\6f" \
|
||
+ "\\6e\\50\\6f\\69\\6e\\74\\30\\81\\be\\06\\08\\2b\\06\\01\\05\\05" \
|
||
+ "\\07\\01\\01\\04\\81\\b1\\30\\81\\ae\\30\\81\\ab\\06\\08\\2b\\06" \
|
||
+ "\\01\\05\\05\\07\\30\\02\\86\\81\\9e\\6c\\64\\61\\70\\3a\\2f\\2f" \
|
||
+ "\\2f\\43\\4e\\3d\\61\\64\\2d\\41\\44\\2d\\53\\45\\52\\56\\45\\52" \
|
||
+ "\\2d\\43\\41\\2c\\43\\4e\\3d\\41\\49\\41\\2c\\43\\4e\\3d\\50\\75" \
|
||
+ "\\62\\6c\\69\\63\\25\\32\\30\\4b\\65\\79\\25\\32\\30\\53\\65\\72" \
|
||
+ "\\76\\69\\63\\65\\73\\2c\\43\\4e\\3d\\53\\65\\72\\76\\69\\63\\65" \
|
||
+ "\\73\\2c\\43\\4e\\3d\\43\\6f\\6e\\66\\69\\67\\75\\72\\61\\74\\69" \
|
||
+ "\\6f\\6e\\2c\\44\\43\\3d\\61\\64\\2c\\44\\43\\3d\\64\\65\\76\\65" \
|
||
+ "\\6c\\3f\\63\\41\\43\\65\\72\\74\\69\\66\\69\\63\\61\\74\\65\\3f" \
|
||
+ "\\62\\61\\73\\65\\3f\\6f\\62\\6a\\65\\63\\74\\43\\6c\\61\\73\\73" \
|
||
+ "\\3d\\63\\65\\72\\74\\69\\66\\69\\63\\61\\74\\69\\6f\\6e\\41\\75" \
|
||
+ "\\74\\68\\6f\\72\\69\\74\\79\\30\\3f\\06\\03\\55\\1d\\11\\04\\38" \
|
||
+ "\\30\\36\\a0\\1c\\06\\0a\\2b\\06\\01\\04\\01\\82\\37\\14\\02\\03" \
|
||
+ "\\a0\\0e\\0c\\0c\\74\\75\\31\\40\\61\\64\\2e\\64\\65\\76\\65\\6c" \
|
||
+ "\\81\\16\\74\\65\\73\\74\\2e\\75\\73\\65\\72\\40\\65\\6d\\61\\69" \
|
||
+ "\\6c\\2e\\64\\6f\\6d\\61\\69\\6e\\30\\0d\\06\\09\\2a\\86\\48\\86" \
|
||
+ "\\f7\\0d\\01\\01\\05\\05\\00\\03\\82\\01\\01\\00\\41\\45\\0a\\6d" \
|
||
+ "\\bb\\7f\\5c\\07\\0c\\c9\\b0\\39\\55\\6d\\7c\\b5\\02\\cd\\e8\\b2" \
|
||
+ "\\e5\\02\\94\\77\\60\\db\\d1\\af\\1d\\db\\44\\5f\\ce\\83\\db\\80" \
|
||
+ "\\2e\\e2\\b2\\08\\25\\82\\14\\cb\\48\\95\\20\\13\\6c\\a9\\aa\\f8" \
|
||
+ "\\31\\56\\ed\\c0\\3b\\d4\\ae\\2e\\e3\\8f\\05\\fc\\ab\\5f\\2a\\69" \
|
||
+ "\\23\\bc\\b8\\8c\\ec\\2d\\a9\\0b\\86\\95\\73\\73\\db\\17\\ce\\c6" \
|
||
+ "\\ae\\c5\\b4\\c1\\25\\87\\3b\\67\\43\\9e\\87\\5a\\e6\\b9\\a0\\28" \
|
||
+ "\\12\\3d\\a8\\2e\\d7\\5e\\ef\\65\\2d\\e6\\a5\\67\\84\\ac\\fd\\31" \
|
||
+ "\\c1\\78\\d8\\72\\51\\a2\\88\\55\\0f\\97\\47\\93\\07\\ea\\8a\\53" \
|
||
+ "\\27\\4e\\34\\54\\34\\1f\\a0\\6a\\03\\44\\fb\\23\\61\\8e\\87\\8e" \
|
||
+ "\\3c\\d0\\8f\\ae\\e4\\cf\\ee\\65\\a8\\ba\\96\\68\\08\\1c\\60\\e2" \
|
||
+ "\\4e\\11\\a3\\74\\b8\\a5\\4e\\ea\\6a\\82\\4c\\c2\\4d\\63\\8e\\9f" \
|
||
+ "\\7c\\2f\\a8\\c0\\62\\f8\\f7\\d9\\25\\c4\\91\\ab\\4d\\6a\\44\\af" \
|
||
+ "\\75\\93\\53\\03\\a4\\99\\c8\\cd\\91\\89\\60\\75\\30\\99\\76\\05" \
|
||
+ "\\5a\\a0\\03\\a7\\a1\\2c\\03\\04\\8f\\d4\\5a\\31\\52\\28\\5a\\e6" \
|
||
+ "\\a2\\d3\\43\\21\\5b\\dc\\a2\\1d\\55\\a9\\48\\c5\\c4\\aa\\f3\\8b" \
|
||
+ "\\e6\\3e\\75\\96\\e4\\3e\\64\\af\\e8\\a7\\6a\\b6"
|
||
+
|
||
+static void test_sss_certmap_get_search_filter(void **state)
|
||
+{
|
||
+ int ret;
|
||
+ struct sss_certmap_ctx *ctx;
|
||
+ char *filter;
|
||
+ char **domains;
|
||
+ const char *dom_list[] = {"test.dom", NULL};
|
||
+
|
||
+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx);
|
||
+ assert_int_equal(ret, EOK);
|
||
+ assert_non_null(ctx);
|
||
+ assert_null(ctx->prio_list);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 100,
|
||
+ "KRB5:<ISSUER>CN=Certificate Authority,O=IPA.DEVEL",
|
||
+ "LDAP:rule100=<I>{issuer_dn}<S>{subject_dn}", NULL);
|
||
+ assert_int_equal(ret, 0);
|
||
+
|
||
+ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert_der),
|
||
+ sizeof(test_cert_der),
|
||
+ &filter, &domains);
|
||
+ assert_int_equal(ret, 0);
|
||
+ assert_non_null(filter);
|
||
+ assert_string_equal(filter, "rule100=<I>CN=Certificate Authority,O=IPA.DEVEL"
|
||
+ "<S>CN=ipa-devel.ipa.devel,O=IPA.DEVEL");
|
||
+ assert_null(domains);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 99,
|
||
+ "KRB5:<ISSUER>CN=Certificate Authority,O=IPA.DEVEL",
|
||
+ "LDAP:rule99=<I>{issuer_dn}<S>{subject_dn}",
|
||
+ dom_list);
|
||
+ assert_int_equal(ret, 0);
|
||
+ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert_der),
|
||
+ sizeof(test_cert_der),
|
||
+ &filter, &domains);
|
||
+ assert_int_equal(ret, 0);
|
||
+ assert_non_null(filter);
|
||
+ assert_string_equal(filter, "rule99=<I>CN=Certificate Authority,O=IPA.DEVEL"
|
||
+ "<S>CN=ipa-devel.ipa.devel,O=IPA.DEVEL");
|
||
+ assert_non_null(domains);
|
||
+ assert_string_equal(domains[0], "test.dom");
|
||
+ assert_null(domains[1]);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 98,
|
||
+ "KRB5:<ISSUER>CN=Certificate Authority,O=IPA.DEVEL",
|
||
+ "LDAP:rule98=userCertificate;binary={cert!bin}",
|
||
+ dom_list);
|
||
+ assert_int_equal(ret, 0);
|
||
+ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert_der),
|
||
+ sizeof(test_cert_der),
|
||
+ &filter, &domains);
|
||
+ assert_int_equal(ret, 0);
|
||
+ assert_non_null(filter);
|
||
+ assert_string_equal(filter, "rule98=userCertificate;binary=" TEST_CERT_BIN);
|
||
+ assert_non_null(domains);
|
||
+ assert_string_equal(domains[0], "test.dom");
|
||
+ assert_null(domains[1]);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 97,
|
||
+ "KRB5:<ISSUER>CN=Certificate Authority,O=IPA.DEVEL",
|
||
+ "LDAP:rule97=<I>{issuer_dn!nss_x500}<S>{subject_dn}",
|
||
+ dom_list);
|
||
+ assert_int_equal(ret, 0);
|
||
+ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert_der),
|
||
+ sizeof(test_cert_der),
|
||
+ &filter, &domains);
|
||
+ assert_int_equal(ret, 0);
|
||
+ assert_non_null(filter);
|
||
+ assert_string_equal(filter, "rule97=<I>O=IPA.DEVEL,CN=Certificate Authority"
|
||
+ "<S>CN=ipa-devel.ipa.devel,O=IPA.DEVEL");
|
||
+ assert_non_null(domains);
|
||
+ assert_string_equal(domains[0], "test.dom");
|
||
+ assert_null(domains[1]);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 96,
|
||
+ "KRB5:<ISSUER>CN=Certificate Authority,O=IPA.DEVEL",
|
||
+ "LDAP:rule96=<I>{issuer_dn!nss_x500}<S>{subject_dn!nss_x500}",
|
||
+ dom_list);
|
||
+ assert_int_equal(ret, 0);
|
||
+ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert_der),
|
||
+ sizeof(test_cert_der),
|
||
+ &filter, &domains);
|
||
+ assert_int_equal(ret, 0);
|
||
+ assert_non_null(filter);
|
||
+ assert_string_equal(filter, "rule96=<I>O=IPA.DEVEL,CN=Certificate Authority"
|
||
+ "<S>O=IPA.DEVEL,CN=ipa-devel.ipa.devel");
|
||
+ assert_non_null(domains);
|
||
+ assert_string_equal(domains[0], "test.dom");
|
||
+ assert_null(domains[1]);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 95,
|
||
+ "KRB5:<ISSUER>CN=Certificate Authority,O=IPA.DEVEL",
|
||
+ NULL, NULL);
|
||
+ assert_int_equal(ret, 0);
|
||
+ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert_der),
|
||
+ sizeof(test_cert_der),
|
||
+ &filter, &domains);
|
||
+ assert_int_equal(ret, 0);
|
||
+ assert_non_null(filter);
|
||
+ assert_string_equal(filter, "(userCertificate;binary=" TEST_CERT_BIN ")");
|
||
+ assert_null(domains);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 94,
|
||
+ "KRB5:<ISSUER>CN=Certificate Authority,O=IPA.DEVEL",
|
||
+ "LDAP:rule94=<I>{issuer_dn!ad_x500}<S>{subject_dn!ad_x500}",
|
||
+ dom_list);
|
||
+ assert_int_equal(ret, 0);
|
||
+ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert_der),
|
||
+ sizeof(test_cert_der),
|
||
+ &filter, &domains);
|
||
+ assert_int_equal(ret, 0);
|
||
+ assert_non_null(filter);
|
||
+ assert_string_equal(filter, "rule94=<I>O=IPA.DEVEL,CN=Certificate Authority"
|
||
+ "<S>O=IPA.DEVEL,CN=ipa-devel.ipa.devel");
|
||
+ assert_non_null(domains);
|
||
+ assert_string_equal(domains[0], "test.dom");
|
||
+ assert_null(domains[1]);
|
||
+
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 89, NULL,
|
||
+ "(rule89={subject_nt_principal})",
|
||
+ NULL);
|
||
+ assert_int_equal(ret, 0);
|
||
+ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert2_der),
|
||
+ sizeof(test_cert2_der),
|
||
+ &filter, &domains);
|
||
+ assert_int_equal(ret, 0);
|
||
+ assert_non_null(filter);
|
||
+ assert_string_equal(filter, "(rule89=tu1@ad.devel)");
|
||
+ assert_null(domains);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 88, NULL,
|
||
+ "(rule88={subject_nt_principal.short_name})",
|
||
+ NULL);
|
||
+ assert_int_equal(ret, 0);
|
||
+ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert2_der),
|
||
+ sizeof(test_cert2_der),
|
||
+ &filter, &domains);
|
||
+ assert_int_equal(ret, 0);
|
||
+ assert_non_null(filter);
|
||
+ assert_string_equal(filter, "(rule88=tu1)");
|
||
+ assert_null(domains);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 87, NULL,
|
||
+ "LDAP:rule87=<I>{issuer_dn!nss_x500}<S>{subject_dn!nss_x500}",
|
||
+ NULL);
|
||
+ assert_int_equal(ret, 0);
|
||
+ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert2_der),
|
||
+ sizeof(test_cert2_der),
|
||
+ &filter, &domains);
|
||
+ assert_int_equal(ret, 0);
|
||
+ assert_non_null(filter);
|
||
+ assert_string_equal(filter, "rule87=<I>DC=devel,DC=ad,CN=ad-AD-SERVER-CA"
|
||
+ "<S>DC=devel,DC=ad,CN=Users,CN=t u,E=test.user@email.domain");
|
||
+ assert_null(domains);
|
||
+
|
||
+ ret = sss_certmap_add_rule(ctx, 86, NULL,
|
||
+ "LDAP:rule86=<I>{issuer_dn!ad_x500}<S>{subject_dn!ad_x500}",
|
||
+ NULL);
|
||
+ assert_int_equal(ret, 0);
|
||
+ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert2_der),
|
||
+ sizeof(test_cert2_der),
|
||
+ &filter, &domains);
|
||
+ assert_int_equal(ret, 0);
|
||
+ assert_non_null(filter);
|
||
+ assert_string_equal(filter, "rule86=<I>DC=devel,DC=ad,CN=ad-AD-SERVER-CA"
|
||
+ "<S>DC=devel,DC=ad,CN=Users,CN=t u,E=test.user@email.domain");
|
||
+ assert_null(domains);
|
||
+
|
||
+
|
||
+ sss_certmap_free_ctx(ctx);
|
||
+
|
||
+ /* check defaults when no rules are added yet */
|
||
+ ret = sss_certmap_init(NULL, ext_debug, NULL, &ctx);
|
||
+ assert_int_equal(ret, EOK);
|
||
+ assert_non_null(ctx);
|
||
+ assert_null(ctx->prio_list);
|
||
+ ret = sss_certmap_get_search_filter(ctx, discard_const(test_cert2_der),
|
||
+ sizeof(test_cert2_der),
|
||
+ &filter, &domains);
|
||
+ assert_int_equal(ret, 0);
|
||
+ assert_non_null(filter);
|
||
+ assert_string_equal(filter, "(userCertificate;binary=" TEST_CERT2_BIN")");
|
||
+ assert_null(domains);
|
||
+}
|
||
+
|
||
+int main(int argc, const char *argv[])
|
||
+{
|
||
+ int rv;
|
||
+ poptContext pc;
|
||
+ int opt;
|
||
+ struct poptOption long_options[] = {
|
||
+ POPT_AUTOHELP
|
||
+ SSSD_DEBUG_OPTS
|
||
+ POPT_TABLEEND
|
||
+ };
|
||
+
|
||
+ const struct CMUnitTest tests[] = {
|
||
+ cmocka_unit_test(test_sss_certmap_init),
|
||
+ cmocka_unit_test(test_sss_certmap_add_rule),
|
||
+ cmocka_unit_test(test_sss_certmap_add_matching_rule),
|
||
+ cmocka_unit_test(test_check_ad_attr_name),
|
||
+ cmocka_unit_test(test_sss_cert_get_content),
|
||
+ cmocka_unit_test(test_sss_cert_get_content_2),
|
||
+ cmocka_unit_test(test_sss_certmap_match_cert),
|
||
+ cmocka_unit_test(test_sss_certmap_add_mapping_rule),
|
||
+ cmocka_unit_test(test_sss_certmap_get_search_filter),
|
||
+ };
|
||
+
|
||
+ /* Set debug level to invalid value so we can deside if -d 0 was used. */
|
||
+ debug_level = SSSDBG_INVALID;
|
||
+
|
||
+ pc = poptGetContext(argv[0], argc, argv, long_options, 0);
|
||
+ while((opt = poptGetNextOpt(pc)) != -1) {
|
||
+ switch(opt) {
|
||
+ default:
|
||
+ fprintf(stderr, "\nInvalid option %s: %s\n\n",
|
||
+ poptBadOption(pc, 0), poptStrerror(opt));
|
||
+ poptPrintUsage(pc, stderr, 0);
|
||
+ return 1;
|
||
+ }
|
||
+ }
|
||
+ poptFreeContext(pc);
|
||
+
|
||
+ DEBUG_CLI_INIT(debug_level);
|
||
+
|
||
+#ifdef HAVE_NSS
|
||
+ nspr_nss_init();
|
||
+#endif
|
||
+
|
||
+ tests_set_cwd();
|
||
+ rv = cmocka_run_group_tests(tests, NULL, NULL);
|
||
+
|
||
+#ifdef HAVE_NSS
|
||
+ /* Cleanup NSS and NSPR to make valgrind happy. */
|
||
+ nspr_nss_cleanup();
|
||
+#endif
|
||
+
|
||
+ return rv;
|
||
+}
|
||
diff --git a/src/tests/dlopen-tests.c b/src/tests/dlopen-tests.c
|
||
index 419857cc739d197493e46629d00aa5fb6cfde824..3914317de90f870fab42d2d72d8e2eb5ea8d9e14 100644
|
||
--- a/src/tests/dlopen-tests.c
|
||
+++ b/src/tests/dlopen-tests.c
|
||
@@ -45,6 +45,7 @@ struct so {
|
||
{ "libsss_idmap.so", { LIBPFX"libsss_idmap.so", NULL } },
|
||
{ "libsss_nss_idmap.so", { LIBPFX"libsss_nss_idmap.so", NULL } },
|
||
{ "libnss_sss.so", { LIBPFX"libnss_sss.so", NULL } },
|
||
+ { "libsss_certmap.so", { LIBPFX"libsss_certmap.so", NULL } },
|
||
{ "pam_sss.so", { LIBPFX"pam_sss.so", NULL } },
|
||
#ifdef BUILD_LIBWBCLIENT
|
||
{ "libwbclient.so", { LIBPFX"libwbclient.so", NULL } },
|
||
--
|
||
2.12.2
|
||
|