diff --git a/Add-PKINIT-UPN-tests-to-t_pkinit.py.patch b/Add-PKINIT-UPN-tests-to-t_pkinit.py.patch new file mode 100644 index 0000000..9a6265f --- /dev/null +++ b/Add-PKINIT-UPN-tests-to-t_pkinit.py.patch @@ -0,0 +1,101 @@ +From 650504957919949aa8ede95fc5e251cdd96e9895 Mon Sep 17 00:00:00 2001 +From: Matt Rogers +Date: Fri, 9 Dec 2016 11:43:27 -0500 +Subject: [PATCH] Add PKINIT UPN tests to t_pkinit.py + +[ghudson@mit.edu: simplify and explain tests; add test for +id-pkinit-san match against canonicalized client principal] + +ticket: 8528 +(cherry picked from commit d520fd3f032121b61b22681838af96ee505fe44d) +--- + src/tests/t_pkinit.py | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 57 insertions(+) + +diff --git a/src/tests/t_pkinit.py b/src/tests/t_pkinit.py +index 526473b42..ac4d326b6 100755 +--- a/src/tests/t_pkinit.py ++++ b/src/tests/t_pkinit.py +@@ -23,6 +23,9 @@ privkey_pem = os.path.join(certs, 'privkey.pem') + privkey_enc_pem = os.path.join(certs, 'privkey-enc.pem') + user_p12 = os.path.join(certs, 'user.p12') + user_enc_p12 = os.path.join(certs, 'user-enc.p12') ++user_upn_p12 = os.path.join(certs, 'user-upn.p12') ++user_upn2_p12 = os.path.join(certs, 'user-upn2.p12') ++user_upn3_p12 = os.path.join(certs, 'user-upn3.p12') + path = os.path.join(os.getcwd(), 'testdir', 'tmp-pkinit-certs') + path_enc = os.path.join(os.getcwd(), 'testdir', 'tmp-pkinit-certs-enc') + +@@ -36,6 +39,20 @@ pkinit_kdc_conf = {'realms': {'$realm': { + restrictive_kdc_conf = {'realms': {'$realm': { + 'restrict_anonymous_to_tgt': 'true' }}} + ++testprincs = {'krbtgt/KRBTEST.COM': {'keys': 'aes128-cts'}, ++ 'user': {'keys': 'aes128-cts', 'flags': '+preauth'}, ++ 'user2': {'keys': 'aes128-cts', 'flags': '+preauth'}} ++alias_kdc_conf = {'realms': {'$realm': { ++ 'default_principal_flags': '+preauth', ++ 'pkinit_eku_checking': 'none', ++ 'pkinit_allow_upn': 'true', ++ 'pkinit_identity': 'FILE:%s,%s' % (kdc_pem, privkey_pem), ++ 'database_module': 'test'}}, ++ 'dbmodules': {'test': { ++ 'db_library': 'test', ++ 'alias': {'user@krbtest.com': 'user'}, ++ 'princs': testprincs}}} ++ + file_identity = 'FILE:%s,%s' % (user_pem, privkey_pem) + file_enc_identity = 'FILE:%s,%s' % (user_pem, privkey_enc_pem) + dir_identity = 'DIR:%s' % path +@@ -45,11 +62,51 @@ dir_file_identity = 'FILE:%s,%s' % (os.path.join(path, 'user.crt'), + dir_file_enc_identity = 'FILE:%s,%s' % (os.path.join(path_enc, 'user.crt'), + os.path.join(path_enc, 'user.key')) + p12_identity = 'PKCS12:%s' % user_p12 ++p12_upn_identity = 'PKCS12:%s' % user_upn_p12 ++p12_upn2_identity = 'PKCS12:%s' % user_upn2_p12 ++p12_upn3_identity = 'PKCS12:%s' % user_upn3_p12 + p12_enc_identity = 'PKCS12:%s' % user_enc_p12 + p11_identity = 'PKCS11:soft-pkcs11.so' + p11_token_identity = ('PKCS11:module_name=soft-pkcs11.so:' + 'slotid=1:token=SoftToken (token)') + ++# Start a realm with the test kdb module for the following UPN SAN tests. ++realm = K5Realm(krb5_conf=pkinit_krb5_conf, kdc_conf=alias_kdc_conf, ++ create_kdb=False) ++realm.start_kdc() ++ ++# Compatibility check: cert contains UPN "user", which matches the ++# request principal user@KRBTEST.COM if parsed as a normal principal. ++realm.kinit(realm.user_princ, ++ flags=['-X', 'X509_user_identity=%s' % p12_upn2_identity]) ++ ++# Compatibility check: cert contains UPN "user@KRBTEST.COM", which matches ++# the request principal user@KRBTEST.COM if parsed as a normal principal. ++realm.kinit(realm.user_princ, ++ flags=['-X', 'X509_user_identity=%s' % p12_upn3_identity]) ++ ++# Cert contains UPN "user@krbtest.com" which is aliased to the request ++# principal. ++realm.kinit(realm.user_princ, ++ flags=['-X', 'X509_user_identity=%s' % p12_upn_identity]) ++ ++# Test an id-pkinit-san match to a post-canonical principal. ++realm.kinit('user@krbtest.com', ++ flags=['-E', '-X', 'X509_user_identity=%s' % p12_identity]) ++ ++# Test a UPN match to a post-canonical principal. (This only works ++# for the cert with the UPN containing just "user", as we don't allow ++# UPN reparsing when comparing to the canonicalized client principal.) ++realm.kinit('user@krbtest.com', ++ flags=['-E', '-X', 'X509_user_identity=%s' % p12_upn2_identity]) ++ ++# Test a mismatch. ++out = realm.run([kinit, '-X', 'X509_user_identity=%s' % p12_upn2_identity, ++ 'user2'], expected_code=1) ++if 'kinit: Client name mismatch while getting initial credentials' not in out: ++ fail('Wrong error for UPN SAN mismatch') ++realm.stop() ++ + realm = K5Realm(krb5_conf=pkinit_krb5_conf, kdc_conf=pkinit_kdc_conf, + get_creds=False) + diff --git a/Add-certauth-pluggable-interface.patch b/Add-certauth-pluggable-interface.patch new file mode 100644 index 0000000..d946c2f --- /dev/null +++ b/Add-certauth-pluggable-interface.patch @@ -0,0 +1,1143 @@ +From ee26c1e3f7e98ed656b154c212bd5a335e87f312 Mon Sep 17 00:00:00 2001 +From: Matt Rogers +Date: Tue, 28 Feb 2017 15:55:24 -0500 +Subject: [PATCH] Add certauth pluggable interface + +Add the header include/krb5/certauth_plugin.h, defining a pluggable +interface to control authorization of PKINIT client certificates. + +Add the "pkinit_san" and "pkinit_eku" builtin certauth modules and +related PKINIT crypto X.509 helper functions. Add authorize_cert() as +the entry function for certauth plugin module checks called in +pkinit_server_verify_padata(). Modify kdcpreauth_moddata to hold the +list of certauth module handles, and load the modules when the PKINIT +kdcpreauth server plugin is initialized. Change +crypto_retrieve_X509_sans() to return ENOENT when no SAN is found. + +Add test modules in plugins/certauth/test. Create t_certauth.py with +basic certauth tests. Add plugin interface documentation in +doc/plugindev/certauth.rst and doc/admin/krb5_conf.rst. + +[ghudson@mit.edu: simplified code, edited docs] + +ticket: 8561 (new) +(cherry picked from commit 6a48b95e3ad65605a657020385b34875677e8b75) +--- + doc/admin/conf_files/krb5_conf.rst | 21 ++ + doc/plugindev/certauth.rst | 27 ++ + doc/plugindev/index.rst | 1 + + src/Makefile.in | 1 + + src/configure.in | 1 + + src/include/Makefile.in | 1 + + src/include/k5-int.h | 3 +- + src/include/krb5/certauth_plugin.h | 103 +++++++ + src/lib/krb5/krb/plugin.c | 3 +- + src/plugins/certauth/test/Makefile.in | 20 ++ + src/plugins/certauth/test/certauth_test.exports | 2 + + src/plugins/certauth/test/deps | 14 + + src/plugins/certauth/test/main.c | 209 +++++++++++++ + src/plugins/preauth/pkinit/pkinit_crypto.h | 4 + + src/plugins/preauth/pkinit/pkinit_crypto_openssl.c | 26 ++ + src/plugins/preauth/pkinit/pkinit_srv.c | 340 ++++++++++++++++++--- + src/plugins/preauth/pkinit/pkinit_trace.h | 5 + + src/tests/Makefile.in | 1 + + src/tests/t_certauth.py | 43 +++ + 19 files changed, 783 insertions(+), 42 deletions(-) + create mode 100644 doc/plugindev/certauth.rst + create mode 100644 src/include/krb5/certauth_plugin.h + create mode 100644 src/plugins/certauth/test/Makefile.in + create mode 100644 src/plugins/certauth/test/certauth_test.exports + create mode 100644 src/plugins/certauth/test/deps + create mode 100644 src/plugins/certauth/test/main.c + create mode 100644 src/tests/t_certauth.py + +diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst +index 653aad613..ac89e3b52 100644 +--- a/doc/admin/conf_files/krb5_conf.rst ++++ b/doc/admin/conf_files/krb5_conf.rst +@@ -858,6 +858,27 @@ built-in modules exist for this interface: + This module authorizes a principal to a local account if the + principal name maps to the local account name. + ++.. _certauth: ++ ++certauth interface ++################## ++ ++The certauth section (introduced in release 1.16) controls modules for ++the certificate authorization interface, which determines whether a ++certificate is allowed to preauthenticate a user via PKINIT. The ++following built-in modules exist for this interface: ++ ++**pkinit_san** ++ This module authorizes the certificate if it contains a PKINIT ++ Subject Alternative Name for the requested client principal, or a ++ Microsoft UPN SAN matching the principal if **pkinit_allow_upn** ++ is set to true for the realm. ++ ++**pkinit_eku** ++ This module rejects the certificate if it does not contain the ++ PKINIT Extended Key Usage attribute consistent with the ++ **pkinit_eku_checking** value for the realm. ++ + + PKINIT options + -------------- +diff --git a/doc/plugindev/certauth.rst b/doc/plugindev/certauth.rst +new file mode 100644 +index 000000000..8b0360327 +--- /dev/null ++++ b/doc/plugindev/certauth.rst +@@ -0,0 +1,27 @@ ++.. _certauth: ++ ++PKINIT certificate authorization interface (certauth) ++===================================================== ++ ++The certauth interface was first introduced in release 1.16. It ++allows customization of the X.509 certificate attribute requirements ++placed on certificates used by PKINIT enabled clients. For a detailed ++description of the certauth interface, see the header file ++```` ++ ++A certauth module implements the **authorize** method to determine ++whether a client's certificate is authorized to authenticate a client ++principal. **authorize** receives the DER-encoded certificate, the ++requested client principal, and a pointer to the client's ++krb5_db_entry (for modules that link against libkdb5). It returns the ++authorization status and optionally outputs a list of authentication ++indicator strings to be added to the ticket. A module must use its ++own internal or library-provided ASN.1 certificate decoder. ++ ++A module can optionally create and destroy module data with the ++**init** and **fini** methods. Module data objects last for the ++lifetime of the KDC process. ++ ++If a module allocates and returns a list of authentication indicators ++from **authorize**, it must also implement the **free_ind** method ++to free the list. +diff --git a/doc/plugindev/index.rst b/doc/plugindev/index.rst +index 3fb921778..67dbc2790 100644 +--- a/doc/plugindev/index.rst ++++ b/doc/plugindev/index.rst +@@ -31,5 +31,6 @@ Contents + profile.rst + gssapi.rst + internal.rst ++ certauth.rst + + .. TODO: GSSAPI mechanism plugins +diff --git a/src/Makefile.in b/src/Makefile.in +index 2ebf2fb4d..b0249778c 100644 +--- a/src/Makefile.in ++++ b/src/Makefile.in +@@ -17,6 +17,7 @@ SUBDIRS=util include lib \ + plugins/pwqual/test \ + plugins/authdata/greet_server \ + plugins/authdata/greet_client \ ++ plugins/certauth/test \ + plugins/kdb/db2 \ + @ldap_plugin_dir@ \ + plugins/kdb/test \ +diff --git a/src/configure.in b/src/configure.in +index acf3a458b..24f653f0d 100644 +--- a/src/configure.in ++++ b/src/configure.in +@@ -1451,6 +1451,7 @@ dnl ccapi ccapi/lib ccapi/lib/unix ccapi/server ccapi/server/unix ccapi/test + + kdc slave config-files build-tools man doc include + ++ plugins/certauth/test + plugins/hostrealm/test + plugins/localauth/test + plugins/kadm5_hook/test +diff --git a/src/include/Makefile.in b/src/include/Makefile.in +index f5b921833..0239338a1 100644 +--- a/src/include/Makefile.in ++++ b/src/include/Makefile.in +@@ -140,6 +140,7 @@ install-headers-unix install: krb5/krb5.h profile.h + $(INSTALL_DATA) $(srcdir)/krb5.h $(DESTDIR)$(KRB5_INCDIR)$(S)krb5.h + $(INSTALL_DATA) $(srcdir)/kdb.h $(DESTDIR)$(KRB5_INCDIR)$(S)kdb.h + $(INSTALL_DATA) krb5/krb5.h $(DESTDIR)$(KRB5_INCDIR)$(S)krb5$(S)krb5.h ++ $(INSTALL_DATA) $(srcdir)/krb5/certauth_plugin.h $(DESTDIR)$(KRB5_INCDIR)$(S)krb5$(S)certauth_plugin.h + $(INSTALL_DATA) $(srcdir)/krb5/ccselect_plugin.h $(DESTDIR)$(KRB5_INCDIR)$(S)krb5$(S)ccselect_plugin.h + $(INSTALL_DATA) $(srcdir)/krb5/clpreauth_plugin.h $(DESTDIR)$(KRB5_INCDIR)$(S)krb5$(S)clpreauth_plugin.h + $(INSTALL_DATA) $(srcdir)/krb5/hostrealm_plugin.h $(DESTDIR)$(KRB5_INCDIR)$(S)krb5$(S)hostrealm_plugin.h +diff --git a/src/include/k5-int.h b/src/include/k5-int.h +index 173cb0264..cea644d0a 100644 +--- a/src/include/k5-int.h ++++ b/src/include/k5-int.h +@@ -1156,7 +1156,8 @@ struct plugin_interface { + #define PLUGIN_INTERFACE_AUDIT 7 + #define PLUGIN_INTERFACE_TLS 8 + #define PLUGIN_INTERFACE_KDCAUTHDATA 9 +-#define PLUGIN_NUM_INTERFACES 10 ++#define PLUGIN_INTERFACE_CERTAUTH 10 ++#define PLUGIN_NUM_INTERFACES 11 + + /* Retrieve the plugin module of type interface_id and name modname, + * storing the result into module. */ +diff --git a/src/include/krb5/certauth_plugin.h b/src/include/krb5/certauth_plugin.h +new file mode 100644 +index 000000000..f22fc1e84 +--- /dev/null ++++ b/src/include/krb5/certauth_plugin.h +@@ -0,0 +1,103 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* include/krb5/certauth_plugin.h - certauth plugin header. */ ++/* ++ * Copyright (C) 2017 by Red Hat, Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in ++ * the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ++ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ++ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ++ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED ++ * OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* ++ * Certificate authorization plugin interface. The PKINIT server module uses ++ * this interface to check client certificate attributes after the certificate ++ * signature has been verified. ++ */ ++#ifndef KRB5_CERTAUTH_PLUGIN_H ++#define KRB5_CERTAUTH_PLUGIN_H ++ ++#include ++#include ++ ++/* Abstract module data type. */ ++typedef struct krb5_certauth_moddata_st *krb5_certauth_moddata; ++ ++typedef struct _krb5_db_entry_new krb5_db_entry; ++ ++/* ++ * Optional: Initialize module data. ++ */ ++typedef krb5_error_code ++(*krb5_certauth_init_fn)(krb5_context context, ++ krb5_certauth_moddata *moddata_out); ++ ++/* ++ * Optional: Clean up the module data. ++ */ ++typedef void ++(*krb5_certauth_fini_fn)(krb5_context context, krb5_certauth_moddata moddata); ++ ++/* ++ * Mandatory: ++ * Return 0 if the DER-encoded cert is authorized for PKINIT authentication by ++ * princ; otherwise return one of the following error codes: ++ * - KRB5KDC_ERR_CLIENT_NAME_MISMATCH - incorrect SAN value ++ * - KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE - incorrect EKU ++ * - KRB5KDC_ERR_CERTIFICATE_MISMATCH - other extension error ++ * - KRB5_PLUGIN_NO_HANDLE - the module has no opinion about cert ++ * ++ * - opts is used by built-in modules to receive internal data, and must be ++ * ignored by other modules. ++ * - db_entry receives the client principal database entry, and can be ignored ++ * by modules that do not link with libkdb5. ++ * - *authinds_out optionally returns a null-terminated list of authentication ++ * indicator strings upon KRB5_PLUGIN_NO_HANDLE or accepted authorization. ++ */ ++typedef krb5_error_code ++(*krb5_certauth_authorize_fn)(krb5_context context, ++ krb5_certauth_moddata moddata, ++ const uint8_t *cert, size_t cert_len, ++ krb5_const_principal princ, const void *opts, ++ const krb5_db_entry *db_entry, ++ char ***authinds_out); ++ ++/* ++ * Free indicators allocated by a module. Mandatory if authorize returns ++ * authentication indicators. ++ */ ++typedef void ++(*krb5_certauth_free_indicator_fn)(krb5_context context, ++ krb5_certauth_moddata moddata, ++ char **authinds); ++ ++typedef struct krb5_certauth_vtable_st { ++ char *name; ++ krb5_certauth_init_fn init; ++ krb5_certauth_fini_fn fini; ++ krb5_certauth_authorize_fn authorize; ++ krb5_certauth_free_indicator_fn free_ind; ++} *krb5_certauth_vtable; ++ ++#endif /* KRB5_CERTAUTH_PLUGIN_H */ +diff --git a/src/lib/krb5/krb/plugin.c b/src/lib/krb5/krb/plugin.c +index 7d64b7c7e..17dd6bd30 100644 +--- a/src/lib/krb5/krb/plugin.c ++++ b/src/lib/krb5/krb/plugin.c +@@ -57,7 +57,8 @@ const char *interface_names[] = { + "hostrealm", + "audit", + "tls", +- "kdcauthdata" ++ "kdcauthdata", ++ "certauth" + }; + + /* Return the context's interface structure for id, or NULL if invalid. */ +diff --git a/src/plugins/certauth/test/Makefile.in b/src/plugins/certauth/test/Makefile.in +new file mode 100644 +index 000000000..d3524084c +--- /dev/null ++++ b/src/plugins/certauth/test/Makefile.in +@@ -0,0 +1,20 @@ ++mydir=plugins$(S)certauth$(S)test ++BUILDTOP=$(REL)..$(S)..$(S).. ++ ++LIBBASE=certauth_test ++LIBMAJOR=0 ++LIBMINOR=0 ++RELDIR=../plugins/certauth/test ++SHLIB_EXPDEPS=$(KRB5_BASE_DEPLIBS) ++SHLIB_EXPLIBS=$(KRB5_BASE_LIBS) ++ ++STLIBOBJS=main.o ++ ++SRCS=$(srcdir)/main.c ++ ++all-unix: all-libs ++install-unix: ++clean-unix:: clean-libs clean-libobjs ++ ++@libnover_frag@ ++@libobj_frag@ +diff --git a/src/plugins/certauth/test/certauth_test.exports b/src/plugins/certauth/test/certauth_test.exports +new file mode 100644 +index 000000000..1c8cd24e2 +--- /dev/null ++++ b/src/plugins/certauth/test/certauth_test.exports +@@ -0,0 +1,2 @@ ++certauth_test1_initvt ++certauth_test2_initvt +diff --git a/src/plugins/certauth/test/deps b/src/plugins/certauth/test/deps +new file mode 100644 +index 000000000..2974b3b57 +--- /dev/null ++++ b/src/plugins/certauth/test/deps +@@ -0,0 +1,14 @@ ++# ++# Generated makefile dependencies follow. ++# ++main.so main.po $(OUTPRE)main.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ ++ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ ++ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \ ++ $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \ ++ $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \ ++ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \ ++ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \ ++ $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ ++ $(top_srcdir)/include/krb5/certauth_plugin.h $(top_srcdir)/include/krb5/plugin.h \ ++ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ ++ main.c +diff --git a/src/plugins/certauth/test/main.c b/src/plugins/certauth/test/main.c +new file mode 100644 +index 000000000..7ef7377fb +--- /dev/null ++++ b/src/plugins/certauth/test/main.c +@@ -0,0 +1,209 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* plugins/certauth/main.c - certauth plugin test modules. */ ++/* ++ * Copyright (C) 2017 by Red Hat, Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in ++ * the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ++ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ++ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ++ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED ++ * OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++#include "krb5/certauth_plugin.h" ++ ++struct krb5_certauth_moddata_st { ++ int initialized; ++}; ++ ++/* Test module 1 returns OK with an indicator. */ ++static krb5_error_code ++test1_authorize(krb5_context context, krb5_certauth_moddata moddata, ++ const uint8_t *cert, size_t cert_len, ++ krb5_const_principal princ, const void *opts, ++ const krb5_db_entry *db_entry, char ***authinds_out) ++{ ++ char **ais = NULL; ++ ++ ais = calloc(2, sizeof(*ais)); ++ assert(ais != NULL); ++ ais[0] = strdup("test1"); ++ assert(ais[0] != NULL); ++ *authinds_out = ais; ++ return KRB5_PLUGIN_NO_HANDLE; ++} ++ ++static void ++test_free_ind(krb5_context context, krb5_certauth_moddata moddata, ++ char **authinds) ++{ ++ size_t i; ++ ++ if (authinds == NULL) ++ return; ++ for (i = 0; authinds[i] != NULL; i++) ++ free(authinds[i]); ++ free(authinds); ++} ++ ++/* A basic moddata test. */ ++static krb5_error_code ++test2_init(krb5_context context, krb5_certauth_moddata *moddata_out) ++{ ++ krb5_certauth_moddata mod; ++ ++ mod = calloc(1, sizeof(*mod)); ++ assert(mod != NULL); ++ mod->initialized = 1; ++ *moddata_out = mod; ++ return 0; ++} ++ ++static void ++test2_fini(krb5_context context, krb5_certauth_moddata moddata) ++{ ++ free(moddata); ++} ++ ++/* Return true if cert appears to contain the CN name, based on a search of the ++ * DER encoding. */ ++static krb5_boolean ++has_cn(krb5_context context, const uint8_t *cert, size_t cert_len, ++ const char *name) ++{ ++ krb5_boolean match = FALSE; ++ uint8_t name_len, cntag[5] = "\x06\x03\x55\x04\x03"; ++ const uint8_t *c; ++ struct k5buf buf; ++ size_t c_left; ++ ++ /* Construct a DER search string of the CN AttributeType encoding followed ++ * by a UTF8String encoding containing name as the AttributeValue. */ ++ k5_buf_init_dynamic(&buf); ++ k5_buf_add_len(&buf, cntag, sizeof(cntag)); ++ k5_buf_add(&buf, "\x0C"); ++ assert(strlen(name) < 128); ++ name_len = strlen(name); ++ k5_buf_add_len(&buf, &name_len, 1); ++ k5_buf_add_len(&buf, name, name_len); ++ assert(k5_buf_status(&buf) == 0); ++ ++ /* Check for the CN needle in the certificate haystack. */ ++ c_left = cert_len; ++ c = memchr(cert, *cntag, c_left); ++ while (c != NULL) { ++ c_left = cert_len - (c - cert); ++ if (buf.len > c_left) ++ break; ++ if (memcmp(c, buf.data, buf.len) == 0) { ++ match = TRUE; ++ break; ++ } ++ assert(c_left >= 1); ++ c = memchr(c + 1, *cntag, c_left - 1); ++ } ++ ++ k5_buf_free(&buf); ++ return match; ++} ++ ++/* ++ * Test module 2 returns OK if princ matches the CN part of the subject name, ++ * and returns indicators of the module name and princ. ++ */ ++static krb5_error_code ++test2_authorize(krb5_context context, krb5_certauth_moddata moddata, ++ const uint8_t *cert, size_t cert_len, ++ krb5_const_principal princ, const void *opts, ++ const krb5_db_entry *db_entry, char ***authinds_out) ++{ ++ krb5_error_code ret; ++ char *name = NULL, **ais = NULL; ++ ++ *authinds_out = NULL; ++ ++ assert(moddata != NULL && moddata->initialized); ++ ++ ret = krb5_unparse_name_flags(context, princ, ++ KRB5_PRINCIPAL_UNPARSE_NO_REALM, &name); ++ if (ret) ++ goto cleanup; ++ ++ if (!has_cn(context, cert, cert_len, name)) { ++ ret = KRB5KDC_ERR_CERTIFICATE_MISMATCH; ++ goto cleanup; ++ } ++ ++ /* Create an indicator list with the module name and CN. */ ++ ais = calloc(3, sizeof(*ais)); ++ assert(ais != NULL); ++ ais[0] = strdup("test2"); ++ ais[1] = strdup(name); ++ assert(ais[0] != NULL && ais[1] != NULL); ++ *authinds_out = ais; ++ ++ ais = NULL; ++ ++cleanup: ++ krb5_free_unparsed_name(context, name); ++ return ret; ++} ++ ++krb5_error_code ++certauth_test1_initvt(krb5_context context, int maj_ver, int min_ver, ++ krb5_plugin_vtable vtable); ++krb5_error_code ++certauth_test1_initvt(krb5_context context, int maj_ver, int min_ver, ++ krb5_plugin_vtable vtable) ++{ ++ krb5_certauth_vtable vt; ++ ++ if (maj_ver != 1) ++ return KRB5_PLUGIN_VER_NOTSUPP; ++ vt = (krb5_certauth_vtable)vtable; ++ vt->name = "test1"; ++ vt->authorize = test1_authorize; ++ vt->free_ind = test_free_ind; ++ return 0; ++} ++ ++krb5_error_code ++certauth_test2_initvt(krb5_context context, int maj_ver, int min_ver, ++ krb5_plugin_vtable vtable); ++krb5_error_code ++certauth_test2_initvt(krb5_context context, int maj_ver, int min_ver, ++ krb5_plugin_vtable vtable) ++{ ++ krb5_certauth_vtable vt; ++ ++ if (maj_ver != 1) ++ return KRB5_PLUGIN_VER_NOTSUPP; ++ vt = (krb5_certauth_vtable)vtable; ++ vt->name = "test2"; ++ vt->authorize = test2_authorize; ++ vt->init = test2_init; ++ vt->fini = test2_fini; ++ vt->free_ind = test_free_ind; ++ return 0; ++} +diff --git a/src/plugins/preauth/pkinit/pkinit_crypto.h b/src/plugins/preauth/pkinit/pkinit_crypto.h +index b483affed..49b96b8ee 100644 +--- a/src/plugins/preauth/pkinit/pkinit_crypto.h ++++ b/src/plugins/preauth/pkinit/pkinit_crypto.h +@@ -664,4 +664,8 @@ extern const size_t krb5_pkinit_sha512_oid_len; + */ + extern krb5_data const * const supported_kdf_alg_ids[]; + ++krb5_error_code ++crypto_encode_der_cert(krb5_context context, pkinit_req_crypto_context reqctx, ++ uint8_t **der_out, size_t *der_len); ++ + #endif /* _PKINIT_CRYPTO_H */ +diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +index 8def8c542..c1276521b 100644 +--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c ++++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +@@ -2137,6 +2137,7 @@ crypto_retrieve_X509_sans(krb5_context context, + + if (!(ext = X509_get_ext(cert, l)) || !(ialt = X509V3_EXT_d2i(ext))) { + pkiDebug("%s: found no subject alt name extensions\n", __FUNCTION__); ++ retval = ENOENT; + goto cleanup; + } + num_sans = sk_GENERAL_NAME_num(ialt); +@@ -6176,3 +6177,28 @@ crypto_get_deferred_ids(krb5_context context, + ret = (const pkinit_deferred_id *)deferred; + return ret; + } ++ ++/* Return the received certificate as DER-encoded data. */ ++krb5_error_code ++crypto_encode_der_cert(krb5_context context, pkinit_req_crypto_context reqctx, ++ uint8_t **der_out, size_t *der_len) ++{ ++ int len; ++ unsigned char *p; ++ ++ *der_out = NULL; ++ *der_len = 0; ++ ++ if (reqctx->received_cert == NULL) ++ return EINVAL; ++ p = NULL; ++ len = i2d_X509(reqctx->received_cert, NULL); ++ if (len <= 0) ++ return EINVAL; ++ p = malloc(len); ++ if (p == NULL) ++ return ENOMEM; ++ *der_out = p; ++ *der_len = len; ++ return 0; ++} +diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c +index b5638a367..23826c5e8 100644 +--- a/src/plugins/preauth/pkinit/pkinit_srv.c ++++ b/src/plugins/preauth/pkinit/pkinit_srv.c +@@ -31,6 +31,25 @@ + + #include + #include "pkinit.h" ++#include "krb5/certauth_plugin.h" ++ ++/* Aliases used by the built-in certauth modules */ ++struct certauth_req_opts { ++ krb5_kdcpreauth_callbacks cb; ++ krb5_kdcpreauth_rock rock; ++ pkinit_kdc_context plgctx; ++ pkinit_kdc_req_context reqctx; ++}; ++ ++typedef struct certauth_module_handle_st { ++ struct krb5_certauth_vtable_st vt; ++ krb5_certauth_moddata moddata; ++} *certauth_handle; ++ ++struct krb5_kdcpreauth_moddata_st { ++ pkinit_kdc_context *realm_contexts; ++ certauth_handle *certauth_modules; ++}; + + static krb5_error_code + pkinit_init_kdc_req_context(krb5_context, pkinit_kdc_req_context *blob); +@@ -51,6 +70,36 @@ pkinit_find_realm_context(krb5_context context, + krb5_kdcpreauth_moddata moddata, + krb5_principal princ); + ++static void ++free_realm_contexts(krb5_context context, pkinit_kdc_context *realm_contexts) ++{ ++ int i; ++ ++ if (realm_contexts == NULL) ++ return; ++ for (i = 0; realm_contexts[i] != NULL; i++) ++ pkinit_server_plugin_fini_realm(context, realm_contexts[i]); ++ pkiDebug("%s: freeing context at %p\n", __FUNCTION__, realm_contexts); ++ free(realm_contexts); ++} ++ ++static void ++free_certauth_handles(krb5_context context, certauth_handle *list) ++{ ++ int i; ++ certauth_handle h; ++ ++ if (list == NULL) ++ return; ++ for (i = 0; list[i] != NULL; i++) { ++ h = list[i]; ++ if (h->vt.fini != NULL) ++ h->vt.fini(context, h->moddata); ++ free(list[i]); ++ } ++ free(list); ++} ++ + static krb5_error_code + pkinit_create_edata(krb5_context context, + pkinit_plg_crypto_context plg_cryptoctx, +@@ -123,7 +172,7 @@ verify_client_san(krb5_context context, + pkinit_kdc_req_context reqctx, + krb5_kdcpreauth_callbacks cb, + krb5_kdcpreauth_rock rock, +- krb5_principal client, ++ krb5_const_principal client, + int *valid_san) + { + krb5_error_code retval; +@@ -134,12 +183,15 @@ verify_client_san(krb5_context context, + char *client_string = NULL, *san_string; + #endif + ++ *valid_san = 0; + retval = crypto_retrieve_cert_sans(context, plgctx->cryptoctx, + reqctx->cryptoctx, plgctx->idctx, + &princs, + plgctx->opts->allow_upn ? &upns : NULL, + NULL); +- if (retval) { ++ if (retval == ENOENT) { ++ goto out; ++ } else if (retval) { + pkiDebug("%s: error from retrieve_certificate_sans()\n", __FUNCTION__); + retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH; + goto out; +@@ -273,6 +325,76 @@ out: + return retval; + } + ++ ++/* Run the received, verified certificate through certauth modules, to verify ++ * that it is authorized to authenticate as client. */ ++static krb5_error_code ++authorize_cert(krb5_context context, certauth_handle *certauth_modules, ++ pkinit_kdc_context plgctx, pkinit_kdc_req_context reqctx, ++ krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock, ++ krb5_principal client) ++{ ++ krb5_error_code ret; ++ certauth_handle hd; ++ struct certauth_req_opts opts; ++ krb5_boolean accepted = FALSE; ++ uint8_t *cert; ++ size_t i, cert_len; ++ void *db_ent = NULL; ++ char **ais = NULL, **ai = NULL; ++ ++ /* Re-encode the received certificate into DER, which is extra work, but ++ * avoids creating a crypto dependency on the interface. */ ++ ret = crypto_encode_der_cert(context, reqctx->cryptoctx, &cert, &cert_len); ++ if (ret) ++ goto cleanup; ++ ++ /* Set options for the builtin module. */ ++ opts.plgctx = plgctx; ++ opts.reqctx = reqctx; ++ opts.cb = cb; ++ opts.rock = rock; ++ ++ db_ent = cb->client_entry(context, rock); ++ ++ /* ++ * Check the certificate against each certauth module. For the certificate ++ * to be authorized at least one module must return 0, and no module can an ++ * error code other than KRB5_PLUGIN_NO_HANDLE (pass). Add indicators from ++ * modules that return 0 or pass. ++ */ ++ ret = KRB5_PLUGIN_NO_HANDLE; ++ for (i = 0; certauth_modules != NULL && certauth_modules[i] != NULL; i++) { ++ hd = certauth_modules[i]; ++ if (hd->vt.authorize == NULL) ++ continue; ++ ++ ret = hd->vt.authorize(context, hd->moddata, cert, cert_len, client, ++ &opts, db_ent, &ais); ++ if (ret == 0) ++ accepted = TRUE; ++ else if (ret != KRB5_PLUGIN_NO_HANDLE) ++ goto cleanup; ++ ++ if (ais != NULL) { ++ /* Assert authentication indicators from the module. */ ++ for (ai = ais; *ai != NULL; ai++) { ++ ret = cb->add_auth_indicator(context, rock, *ai); ++ if (ret) ++ goto cleanup; ++ } ++ hd->vt.free_ind(context, hd->moddata, ais); ++ ais = NULL; ++ } ++ } ++ ++ ret = accepted ? 0 : KRB5KDC_ERR_CLIENT_NAME_MISMATCH; ++ ++cleanup: ++ free(cert); ++ return ret; ++} ++ + static void + pkinit_server_verify_padata(krb5_context context, + krb5_data *req_pkt, +@@ -295,7 +417,6 @@ pkinit_server_verify_padata(krb5_context context, + pkinit_kdc_req_context reqctx = NULL; + krb5_checksum cksum = {0, 0, 0, NULL}; + krb5_data *der_req = NULL; +- int valid_eku = 0, valid_san = 0; + krb5_data k5data; + int is_signed = 1; + krb5_pa_data **e_data = NULL; +@@ -388,27 +509,11 @@ pkinit_server_verify_padata(krb5_context context, + goto cleanup; + } + if (is_signed) { +- +- retval = verify_client_san(context, plgctx, reqctx, cb, rock, +- request->client, &valid_san); +- if (retval) +- goto cleanup; +- if (!valid_san) { +- pkiDebug("%s: did not find an acceptable SAN in user " +- "certificate\n", __FUNCTION__); +- retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH; +- goto cleanup; +- } +- retval = verify_client_eku(context, plgctx, reqctx, &valid_eku); ++ retval = authorize_cert(context, moddata->certauth_modules, plgctx, ++ reqctx, cb, rock, request->client); + if (retval) + goto cleanup; + +- if (!valid_eku) { +- pkiDebug("%s: did not find an acceptable EKU in user " +- "certificate\n", __FUNCTION__); +- retval = KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE; +- goto cleanup; +- } + } else { /* !is_signed */ + if (!krb5_principal_compare(context, request->client, + krb5_anonymous_principal())) { +@@ -1245,11 +1350,15 @@ pkinit_find_realm_context(krb5_context context, + krb5_principal princ) + { + int i; +- pkinit_kdc_context *realm_contexts = (pkinit_kdc_context *)moddata; ++ pkinit_kdc_context *realm_contexts; + + if (moddata == NULL) + return NULL; + ++ realm_contexts = moddata->realm_contexts; ++ if (realm_contexts == NULL) ++ return NULL; ++ + for (i = 0; realm_contexts[i] != NULL; i++) { + pkinit_kdc_context p = realm_contexts[i]; + +@@ -1331,6 +1440,155 @@ errout: + return retval; + } + ++static krb5_error_code ++pkinit_san_authorize(krb5_context context, krb5_certauth_moddata moddata, ++ const uint8_t *cert, size_t cert_len, ++ krb5_const_principal princ, const void *opts, ++ const krb5_db_entry *db_entry, char ***authinds_out) ++{ ++ krb5_error_code ret; ++ int valid_san; ++ const struct certauth_req_opts *req_opts = opts; ++ ++ *authinds_out = NULL; ++ ++ ret = verify_client_san(context, req_opts->plgctx, req_opts->reqctx, ++ req_opts->cb, req_opts->rock, princ, &valid_san); ++ if (ret == ENOENT) ++ return KRB5_PLUGIN_NO_HANDLE; ++ else if (ret) ++ return ret; ++ ++ if (!valid_san) { ++ pkiDebug("%s: did not find an acceptable SAN in user certificate\n", ++ __FUNCTION__); ++ return KRB5KDC_ERR_CLIENT_NAME_MISMATCH; ++ } ++ ++ return 0; ++} ++ ++static krb5_error_code ++pkinit_eku_authorize(krb5_context context, krb5_certauth_moddata moddata, ++ const uint8_t *cert, size_t cert_len, ++ krb5_const_principal princ, const void *opts, ++ const krb5_db_entry *db_entry, char ***authinds_out) ++{ ++ krb5_error_code ret; ++ int valid_eku; ++ const struct certauth_req_opts *req_opts = opts; ++ ++ *authinds_out = NULL; ++ ++ /* Verify the client EKU. */ ++ ret = verify_client_eku(context, req_opts->plgctx, req_opts->reqctx, ++ &valid_eku); ++ if (ret) ++ return ret; ++ ++ if (!valid_eku) { ++ pkiDebug("%s: did not find an acceptable EKU in user certificate\n", ++ __FUNCTION__); ++ return KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE; ++ } ++ ++ return 0; ++} ++ ++static krb5_error_code ++certauth_pkinit_san_initvt(krb5_context context, int maj_ver, int min_ver, ++ krb5_plugin_vtable vtable) ++{ ++ krb5_certauth_vtable vt; ++ ++ if (maj_ver != 1) ++ return KRB5_PLUGIN_VER_NOTSUPP; ++ vt = (krb5_certauth_vtable)vtable; ++ vt->name = "pkinit_san"; ++ vt->authorize = pkinit_san_authorize; ++ return 0; ++} ++ ++static krb5_error_code ++certauth_pkinit_eku_initvt(krb5_context context, int maj_ver, int min_ver, ++ krb5_plugin_vtable vtable) ++{ ++ krb5_certauth_vtable vt; ++ ++ if (maj_ver != 1) ++ return KRB5_PLUGIN_VER_NOTSUPP; ++ vt = (krb5_certauth_vtable)vtable; ++ vt->name = "pkinit_eku"; ++ vt->authorize = pkinit_eku_authorize; ++ return 0; ++} ++ ++static krb5_error_code ++load_certauth_plugins(krb5_context context, certauth_handle **handle_out) ++{ ++ krb5_error_code ret; ++ krb5_plugin_initvt_fn *modules = NULL, *mod; ++ certauth_handle *list = NULL, h; ++ size_t count; ++ ++ /* Register the builtin modules. */ ++ ret = k5_plugin_register(context, PLUGIN_INTERFACE_CERTAUTH, ++ "pkinit_san", certauth_pkinit_san_initvt); ++ if (ret) ++ goto cleanup; ++ ++ ret = k5_plugin_register(context, PLUGIN_INTERFACE_CERTAUTH, ++ "pkinit_eku", certauth_pkinit_eku_initvt); ++ if (ret) ++ goto cleanup; ++ ++ ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_CERTAUTH, &modules); ++ if (ret) ++ goto cleanup; ++ ++ /* Allocate handle list. */ ++ for (count = 0; modules[count]; count++); ++ list = k5calloc(count + 1, sizeof(*list), &ret); ++ if (list == NULL) ++ goto cleanup; ++ ++ /* Initialize each module, ignoring ones that fail. */ ++ count = 0; ++ for (mod = modules; *mod != NULL; mod++) { ++ h = k5calloc(1, sizeof(*h), &ret); ++ if (h == NULL) ++ goto cleanup; ++ ++ ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&h->vt); ++ if (ret) { ++ TRACE_CERTAUTH_VTINIT_FAIL(context, ret); ++ free(h); ++ continue; ++ } ++ h->moddata = NULL; ++ if (h->vt.init != NULL) { ++ ret = h->vt.init(context, &h->moddata); ++ if (ret) { ++ TRACE_CERTAUTH_INIT_FAIL(context, h->vt.name, ret); ++ free(h); ++ continue; ++ } ++ } ++ list[count++] = h; ++ list[count] = NULL; ++ } ++ list[count] = NULL; ++ ++ ret = 0; ++ *handle_out = list; ++ list = NULL; ++ ++cleanup: ++ k5_plugin_free_modules(context, modules); ++ free_certauth_handles(context, list); ++ return ret; ++} ++ + static int + pkinit_server_plugin_init(krb5_context context, + krb5_kdcpreauth_moddata *moddata_out, +@@ -1338,6 +1596,8 @@ pkinit_server_plugin_init(krb5_context context, + { + krb5_error_code retval = ENOMEM; + pkinit_kdc_context plgctx, *realm_contexts = NULL; ++ certauth_handle *certauth_modules = NULL; ++ krb5_kdcpreauth_moddata moddata; + size_t i, j; + size_t numrealms; + +@@ -1368,16 +1628,22 @@ pkinit_server_plugin_init(krb5_context context, + goto errout; + } + +- *moddata_out = (krb5_kdcpreauth_moddata)realm_contexts; +- retval = 0; +- pkiDebug("%s: returning context at %p\n", __FUNCTION__, realm_contexts); ++ retval = load_certauth_plugins(context, &certauth_modules); ++ if (retval) ++ goto errout; ++ ++ moddata = k5calloc(1, sizeof(*moddata), &retval); ++ if (moddata == NULL) ++ goto errout; ++ moddata->realm_contexts = realm_contexts; ++ moddata->certauth_modules = certauth_modules; ++ *moddata_out = moddata; ++ pkiDebug("%s: returning context at %p\n", __FUNCTION__, moddata); ++ return 0; + + errout: +- if (retval) { +- pkinit_server_plugin_fini(context, +- (krb5_kdcpreauth_moddata)realm_contexts); +- } +- ++ free_realm_contexts(context, realm_contexts); ++ free_certauth_handles(context, certauth_modules); + return retval; + } + +@@ -1405,17 +1671,11 @@ static void + pkinit_server_plugin_fini(krb5_context context, + krb5_kdcpreauth_moddata moddata) + { +- pkinit_kdc_context *realm_contexts = (pkinit_kdc_context *)moddata; +- int i; +- +- if (realm_contexts == NULL) ++ if (moddata == NULL) + return; +- +- for (i = 0; realm_contexts[i] != NULL; i++) { +- pkinit_server_plugin_fini_realm(context, realm_contexts[i]); +- } +- pkiDebug("%s: freeing context at %p\n", __FUNCTION__, realm_contexts); +- free(realm_contexts); ++ free_realm_contexts(context, moddata->realm_contexts); ++ free_certauth_handles(context, moddata->certauth_modules); ++ free(moddata); + } + + static krb5_error_code +diff --git a/src/plugins/preauth/pkinit/pkinit_trace.h b/src/plugins/preauth/pkinit/pkinit_trace.h +index b3f5cbb20..458d0961e 100644 +--- a/src/plugins/preauth/pkinit/pkinit_trace.h ++++ b/src/plugins/preauth/pkinit/pkinit_trace.h +@@ -91,4 +91,9 @@ + #define TRACE_PKINIT_OPENSSL_ERROR(c, msg) \ + TRACE(c, "PKINIT OpenSSL error: {str}", msg) + ++#define TRACE_CERTAUTH_VTINIT_FAIL(c, ret) \ ++ TRACE(c, "certauth module failed to init vtable: {kerr}", ret) ++#define TRACE_CERTAUTH_INIT_FAIL(c, name, ret) \ ++ TRACE(c, "certauth module {str} failed to init: {kerr}", name, ret) ++ + #endif /* PKINIT_TRACE_H */ +diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in +index b55469146..0e93d6b59 100644 +--- a/src/tests/Makefile.in ++++ b/src/tests/Makefile.in +@@ -167,6 +167,7 @@ check-pytests: localauth plugorder rdreq responder s2p s4u2proxy unlockiter + $(RUNPYTEST) $(srcdir)/t_preauth.py $(PYTESTFLAGS) + $(RUNPYTEST) $(srcdir)/t_princflags.py $(PYTESTFLAGS) + $(RUNPYTEST) $(srcdir)/t_tabdump.py $(PYTESTFLAGS) ++ $(RUNPYTEST) $(srcdir)/t_certauth.py $(PYTESTFLAGS) + + clean: + $(RM) adata etinfo forward gcred hist hooks hrealm icred kdbtest +diff --git a/src/tests/t_certauth.py b/src/tests/t_certauth.py +new file mode 100644 +index 000000000..ca7df2b42 +--- /dev/null ++++ b/src/tests/t_certauth.py +@@ -0,0 +1,43 @@ ++#!/usr/bin/python ++from k5test import * ++ ++certs = os.path.join(srctop, 'tests', 'dejagnu', 'pkinit-certs') ++ca_pem = os.path.join(certs, 'ca.pem') ++kdc_pem = os.path.join(certs, 'kdc.pem') ++privkey_pem = os.path.join(certs, 'privkey.pem') ++user_pem = os.path.join(certs, 'user.pem') ++ ++modpath = os.path.join(buildtop, 'plugins', 'certauth', 'test', ++ 'certauth_test.so') ++pkinit_krb5_conf = {'realms': {'$realm': { ++ 'pkinit_anchors': 'FILE:%s' % ca_pem}}, ++ 'plugins': {'certauth': {'module': ['test1:' + modpath, ++ 'test2:' + modpath], ++ 'enable_only': ['test1', 'test2']}}} ++pkinit_kdc_conf = {'realms': {'$realm': { ++ 'default_principal_flags': '+preauth', ++ 'pkinit_eku_checking': 'none', ++ 'pkinit_identity': 'FILE:%s,%s' % (kdc_pem, privkey_pem), ++ 'pkinit_indicator': ['indpkinit1', 'indpkinit2']}}} ++ ++file_identity = 'FILE:%s,%s' % (user_pem, privkey_pem) ++ ++realm = K5Realm(krb5_conf=pkinit_krb5_conf, kdc_conf=pkinit_kdc_conf, ++ get_creds=False) ++ ++# Let the test module match user to CN=user, with indicators. ++realm.kinit(realm.user_princ, ++ flags=['-X', 'X509_user_identity=%s' % file_identity]) ++realm.klist(realm.user_princ) ++realm.run([kvno, realm.host_princ]) ++realm.run(['./adata', realm.host_princ], ++ expected_msg='+97: [test1, test2, user, indpkinit1, indpkinit2]') ++ ++# Let the test module mismatch with user2 to CN=user. ++realm.addprinc("user2@KRBTEST.COM") ++out = realm.kinit("user2@KRBTEST.COM", ++ flags=['-X', 'X509_user_identity=%s' % file_identity], ++ expected_code=1, ++ expected_msg='kinit: Certificate mismatch') ++ ++success("certauth tests") diff --git a/Add-test-cert-generation-to-make-certs.sh.patch b/Add-test-cert-generation-to-make-certs.sh.patch new file mode 100644 index 0000000..8c5ed10 --- /dev/null +++ b/Add-test-cert-generation-to-make-certs.sh.patch @@ -0,0 +1,968 @@ +From ee266c55e8f4864dfca4415aaf53ae63587378b7 Mon Sep 17 00:00:00 2001 +From: Matt Rogers +Date: Mon, 5 Dec 2016 12:22:45 -0500 +Subject: [PATCH] Add test cert generation to make-certs.sh + +Add additional test certificates for UPN matching. Run make-certs.sh +to regenerate certs. + +ticket: 8528 +(cherry picked from commit 5a1d0388ba2e4ec510ed715ce5fbc7f748941425) +--- + src/tests/dejagnu/pkinit-certs/ca.pem | 54 ++++++++++++------------ + src/tests/dejagnu/pkinit-certs/kdc.pem | 50 ++++++++++++---------- + src/tests/dejagnu/pkinit-certs/make-certs.sh | 53 ++++++++++++++++++++++- + src/tests/dejagnu/pkinit-certs/privkey-enc.pem | 52 +++++++++++------------ + src/tests/dejagnu/pkinit-certs/privkey.pem | 50 +++++++++++----------- + src/tests/dejagnu/pkinit-certs/user-enc.p12 | Bin 3029 -> 2837 bytes + src/tests/dejagnu/pkinit-certs/user-upn.p12 | Bin 0 -> 2829 bytes + src/tests/dejagnu/pkinit-certs/user-upn.pem | 28 +++++++++++++ + src/tests/dejagnu/pkinit-certs/user-upn2.p12 | Bin 0 -> 2813 bytes + src/tests/dejagnu/pkinit-certs/user-upn2.pem | 28 +++++++++++++ + src/tests/dejagnu/pkinit-certs/user-upn3.csr | 16 +++++++ + src/tests/dejagnu/pkinit-certs/user-upn3.p12 | Bin 0 -> 2829 bytes + src/tests/dejagnu/pkinit-certs/user-upn3.pem | 28 +++++++++++++ + src/tests/dejagnu/pkinit-certs/user.p12 | Bin 3104 -> 2837 bytes + src/tests/dejagnu/pkinit-certs/user.pem | 56 ++++++++++++------------- + 15 files changed, 283 insertions(+), 132 deletions(-) + create mode 100644 src/tests/dejagnu/pkinit-certs/user-upn.p12 + create mode 100644 src/tests/dejagnu/pkinit-certs/user-upn.pem + create mode 100644 src/tests/dejagnu/pkinit-certs/user-upn2.p12 + create mode 100644 src/tests/dejagnu/pkinit-certs/user-upn2.pem + create mode 100644 src/tests/dejagnu/pkinit-certs/user-upn3.csr + create mode 100644 src/tests/dejagnu/pkinit-certs/user-upn3.p12 + create mode 100644 src/tests/dejagnu/pkinit-certs/user-upn3.pem + +diff --git a/src/tests/dejagnu/pkinit-certs/ca.pem b/src/tests/dejagnu/pkinit-certs/ca.pem +index 55fe02c92..44c917687 100644 +--- a/src/tests/dejagnu/pkinit-certs/ca.pem ++++ b/src/tests/dejagnu/pkinit-certs/ca.pem +@@ -1,29 +1,29 @@ + -----BEGIN CERTIFICATE----- +-MIIE5TCCA82gAwIBAgIJANsFDWp1HgAaMA0GCSqGSIb3DQEBBQUAMIGnMQswCQYD +-VQQGEwJVUzEWMBQGA1UECBMNTWFzc2FjaHVzZXR0czESMBAGA1UEBxMJQ2FtYnJp +-ZGdlMQwwCgYDVQQKEwNNSVQxKTAnBgNVBAsTIEluc2VjdXJlIFBraW5pdCBLZXJi +-ZXJvcyB0ZXN0IENBMTMwMQYDVQQDFCpwa2luaXQgdGVzdCBzdWl0ZSBDQTsgZG8g +-bm90IHVzZSBvdGhlcndpc2UwHhcNMTAwMTA2MTQ1MTI3WhcNMjMwOTE1MTQ1MTI3 +-WjCBpzELMAkGA1UEBhMCVVMxFjAUBgNVBAgTDU1hc3NhY2h1c2V0dHMxEjAQBgNV +-BAcTCUNhbWJyaWRnZTEMMAoGA1UEChMDTUlUMSkwJwYDVQQLEyBJbnNlY3VyZSBQ +-a2luaXQgS2VyYmVyb3MgdGVzdCBDQTEzMDEGA1UEAxQqcGtpbml0IHRlc3Qgc3Vp +-dGUgQ0E7IGRvIG5vdCB1c2Ugb3RoZXJ3aXNlMIIBIjANBgkqhkiG9w0BAQEFAAOC +-AQ8AMIIBCgKCAQEAnYLMe58ny00MgskJP7tZ3PIQRpQkXGLJZKI0HfntCRbIuvmn +-ZejPSKdNMyejzRIyjdw1FDJUAnpXYcic3TD5817G5H63UrllAGuy+lhQWNzE6c6K +-ueerevR3pMaqHXonaflVasUu5e2AAWVnFbz4x04uLlQejqPwm5sR1xTeLUnVfSY7 +-5NbXGIE488iDV0wW8nqGoVWn/TsRd+7KuQUIkJpt8+V6Jk6hPIcPqe6h7mXNGsgc +-5dBSqBwVcjU9DbeT4xxxEmgQdLt7qdNwV1ZPLQnTQpogNrT5uf3oSbOTsyM02GOW +-riIRmsqq81sfMrpviTRRDwoqTUEhoCSor0UmcwIDAQABo4IBEDCCAQwwHQYDVR0O +-BBYEFFn82RUKgTvkFn0cgwyCQpNeWCxYMIHcBgNVHSMEgdQwgdGAFFn82RUKgTvk +-Fn0cgwyCQpNeWCxYoYGtpIGqMIGnMQswCQYDVQQGEwJVUzEWMBQGA1UECBMNTWFz +-c2FjaHVzZXR0czESMBAGA1UEBxMJQ2FtYnJpZGdlMQwwCgYDVQQKEwNNSVQxKTAn +-BgNVBAsTIEluc2VjdXJlIFBraW5pdCBLZXJiZXJvcyB0ZXN0IENBMTMwMQYDVQQD +-FCpwa2luaXQgdGVzdCBzdWl0ZSBDQTsgZG8gbm90IHVzZSBvdGhlcndpc2WCCQDb +-BQ1qdR4AGjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQBVL2Q6Xubs +-gm881cAy6esku17/BSTZur7hCLHTGof1ZKNcCXALjmwNYNC3tl6owqpX8CSdBdsD +-Bw/Vs9p3mqnaVEoZc8uW8zS6LoAQbcqiYdQHdEXMh3ec8uvAfmdlQsIsm5Ux8q8L +-NM6bKnUOqOFOHme+RC4FGOLb8JqnnuQdwyIZaUyQP6hXbw4zyDphfgo1ZlZn20xh +-I555kPfAZKEi/d3WY0oN4k+sfCs9tWRNjmqZfKkH1OqRpjCFGG0b0vY77MFRMuPz +-YtN2iD3plgla7KkUMljp9th/Z8Ok79uA1TNLYKzoBjlAX0vToxfa8rrSNo1dHFKT +-e5Tj7+29DE4I ++MIIE5TCCA82gAwIBAgIBATANBgkqhkiG9w0BAQsFADCBpzELMAkGA1UEBhMCVVMx ++FjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxEjAQBgNVBAcMCUNhbWJyaWRnZTEMMAoG ++A1UECgwDTUlUMSkwJwYDVQQLDCBJbnNlY3VyZSBQS0lOSVQgS2VyYmVyb3MgdGVz ++dCBDQTEzMDEGA1UEAwwqcGtpbml0IHRlc3Qgc3VpdGUgQ0E7IGRvIG5vdCB1c2Ug ++b3RoZXJ3aXNlMB4XDTE2MTIxMjE0NDYzOVoXDTI3MTEyNTE0NDYzOVowgacxCzAJ ++BgNVBAYTAlVTMRYwFAYDVQQIDA1NYXNzYWNodXNldHRzMRIwEAYDVQQHDAlDYW1i ++cmlkZ2UxDDAKBgNVBAoMA01JVDEpMCcGA1UECwwgSW5zZWN1cmUgUEtJTklUIEtl ++cmJlcm9zIHRlc3QgQ0ExMzAxBgNVBAMMKnBraW5pdCB0ZXN0IHN1aXRlIENBOyBk ++byBub3QgdXNlIG90aGVyd2lzZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ++ggEBANOWvXDyubZ/Kf8QYdPSRk/rsogzqS0rycNEJp/6rPpTS40UxGae5MyLHfmN ++l2mSevRoHSqhb7cfT6n9kR2kb3HB0qhhhecHey4sGwd+m7WMhBQgVtYaiWkuEQDC ++7/SWkRYzmYX8J41vrQulXU2/2pOQCmG4NKPsNo+vcKoT2SHl6qr3lflUaIG0wDu4 ++bFrWszkxcuSkU7SSXDf2xTTTJ8QftO6WQY3g0+dAhbjZFKxRO5uipxURez5EemVs ++Re86vXEILka85tiVS4maCn3l3FWMqcBHRFNa+/osTb0J/OmvvdQ3bzvscG7KDRtM ++bRUnpWClr5R+AbGVvKocj5I1+G0CAwEAAaOCARgwggEUMB0GA1UdDgQWBBRrwMkO ++fMoN3ofjotSWjK0c27fYYjCB1AYDVR0jBIHMMIHJgBRrwMkOfMoN3ofjotSWjK0c ++27fYYqGBraSBqjCBpzELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDU1hc3NhY2h1c2V0 ++dHMxEjAQBgNVBAcMCUNhbWJyaWRnZTEMMAoGA1UECgwDTUlUMSkwJwYDVQQLDCBJ ++bnNlY3VyZSBQS0lOSVQgS2VyYmVyb3MgdGVzdCBDQTEzMDEGA1UEAwwqcGtpbml0 ++IHRlc3Qgc3VpdGUgQ0E7IGRvIG5vdCB1c2Ugb3RoZXJ3aXNlggEBMAsGA1UdDwQE ++AwIB/jAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAN82zurZwM ++TugUG6b1symxXxOdDqwinwIlQjzXJ8mTRv31q+YwNdYvdWn1aex8v44qjFDjEP80 ++83y18CjjBHznwxsHll80QmFHjpy6xtRrUC/Ak7jfKnDiTKQYBdgmF4/UiVQu354e ++QI6jPMQlrWZXThlRuBjM55hs4tgRYeTgbd4VSZzVQXdm2ViZkg8SGqw0R2ZRnG91 ++dfXkhu/tTruguPAT3MQ2pTK/CoHHA4W2piQbBDqIl83fphRhYxyW/cCF2mvZZUhE ++AfWhgYDeTDxHKG3Jfmm+ujMo5HscgeUpJ7XjZdobNhkQjD1piyuGzFkUfo2XzA6m ++kMz4Jq4cnvpz + -----END CERTIFICATE----- +diff --git a/src/tests/dejagnu/pkinit-certs/kdc.pem b/src/tests/dejagnu/pkinit-certs/kdc.pem +index 5575ab579..8820ad447 100644 +--- a/src/tests/dejagnu/pkinit-certs/kdc.pem ++++ b/src/tests/dejagnu/pkinit-certs/kdc.pem +@@ -1,25 +1,29 @@ + -----BEGIN CERTIFICATE----- +-MIIEMjCCAxqgAwIBAgIBAjANBgkqhkiG9w0BAQUFADCBpzELMAkGA1UEBhMCVVMx +-FjAUBgNVBAgTDU1hc3NhY2h1c2V0dHMxEjAQBgNVBAcTCUNhbWJyaWRnZTEMMAoG +-A1UEChMDTUlUMSkwJwYDVQQLEyBJbnNlY3VyZSBQa2luaXQgS2VyYmVyb3MgdGVz +-dCBDQTEzMDEGA1UEAxQqcGtpbml0IHRlc3Qgc3VpdGUgQ0E7IGRvIG5vdCB1c2Ug +-b3RoZXJ3aXNlMB4XDTEwMDEwNjE0NTgwOFoXDTIzMDkxNTE0NTgwOFowSjELMAkG +-A1UEBhMCVVMxFjAUBgNVBAgTDU1hc3NhY2h1c2V0dHMxFTATBgNVBAoTDEtSQlRF +-U1QuQ09NIDEMMAoGA1UECxMDS0RDMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +-CgKCAQEAnYLMe58ny00MgskJP7tZ3PIQRpQkXGLJZKI0HfntCRbIuvmnZejPSKdN +-MyejzRIyjdw1FDJUAnpXYcic3TD5817G5H63UrllAGuy+lhQWNzE6c6KueerevR3 +-pMaqHXonaflVasUu5e2AAWVnFbz4x04uLlQejqPwm5sR1xTeLUnVfSY75NbXGIE4 +-88iDV0wW8nqGoVWn/TsRd+7KuQUIkJpt8+V6Jk6hPIcPqe6h7mXNGsgc5dBSqBwV +-cjU9DbeT4xxxEmgQdLt7qdNwV1ZPLQnTQpogNrT5uf3oSbOTsyM02GOWriIRmsqq +-81sfMrpviTRRDwoqTUEhoCSor0UmcwIDAQABo4HEMIHBMAkGA1UdEwQCMAAwCwYD +-VR0PBAQDAgPoMBIGA1UdJQQLMAkGBysGAQUCAwUwHQYDVR0OBBYEFFn82RUKgTvk +-Fn0cgwyCQpNeWCxYMB8GA1UdIwQYMBaAFFn82RUKgTvkFn0cgwyCQpNeWCxYMAkG +-A1UdEgQCMAAwSAYDVR0RBEEwP6A9BgYrBgEFAgKgMzAxoA0bC0tSQlRFU1QuQ09N +-oSAwHqADAgEBoRcwFRsGa3JidGd0GwtLUkJURVNULkNPTTANBgkqhkiG9w0BAQUF +-AAOCAQEAP0byILHLWPyGlv/1HN34DfIpLdVkgGar2yceMtZ2v/7UjeA5PlZc8DFM +-20bTq/vIN0eWDTPLI57e+MzQTMxs2UHsic4su0m5DG0cvQTsBXRK51CW/qUF+4n0 +-qSEORULiDF6LNoo8akoLukNBhzBh+aqYt4aB46hhsmDmNZTDP1CXsNGHQI9/L52l +-oqpUGx8tBpKIFos95PSajXrQn2u66rSMMi4aawitM2igurHPDMbC+XvEYMtXpOS5 +-3PEzXEYiSV3TWLTzIE9ytswHeZyHCbp7XHx0LVZFxzqtIe4qmwJJOGhlbH21Izr4 +-feF5h5e2ZrOVREY4cKkJmJhEwsqBVA== ++MIIE4TCCA8mgAwIBAgIBAjANBgkqhkiG9w0BAQsFADCBpzELMAkGA1UEBhMCVVMx ++FjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxEjAQBgNVBAcMCUNhbWJyaWRnZTEMMAoG ++A1UECgwDTUlUMSkwJwYDVQQLDCBJbnNlY3VyZSBQS0lOSVQgS2VyYmVyb3MgdGVz ++dCBDQTEzMDEGA1UEAwwqcGtpbml0IHRlc3Qgc3VpdGUgQ0E7IGRvIG5vdCB1c2Ug ++b3RoZXJ3aXNlMB4XDTE2MTIxMjE0NDYzOVoXDTI3MTEyNTE0NDYzOVowSTELMAkG ++A1UEBhMCVVMxFjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxFDASBgNVBAoMC0tSQlRF ++U1QuQ09NMQwwCgYDVQQDDANLREMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK ++AoIBAQDTlr1w8rm2fyn/EGHT0kZP67KIM6ktK8nDRCaf+qz6U0uNFMRmnuTMix35 ++jZdpknr0aB0qoW+3H0+p/ZEdpG9xwdKoYYXnB3suLBsHfpu1jIQUIFbWGolpLhEA ++wu/0lpEWM5mF/CeNb60LpV1Nv9qTkAphuDSj7DaPr3CqE9kh5eqq95X5VGiBtMA7 ++uGxa1rM5MXLkpFO0klw39sU00yfEH7TulkGN4NPnQIW42RSsUTuboqcVEXs+RHpl ++bEXvOr1xCC5GvObYlUuJmgp95dxVjKnAR0RTWvv6LE29Cfzpr73UN2877HBuyg0b ++TG0VJ6Vgpa+UfgGxlbyqHI+SNfhtAgMBAAGjggFzMIIBbzAdBgNVHQ4EFgQUa8DJ ++DnzKDd6H46LUloytHNu32GIwgdQGA1UdIwSBzDCByYAUa8DJDnzKDd6H46LUloyt ++HNu32GKhga2kgaowgacxCzAJBgNVBAYTAlVTMRYwFAYDVQQIDA1NYXNzYWNodXNl ++dHRzMRIwEAYDVQQHDAlDYW1icmlkZ2UxDDAKBgNVBAoMA01JVDEpMCcGA1UECwwg ++SW5zZWN1cmUgUEtJTklUIEtlcmJlcm9zIHRlc3QgQ0ExMzAxBgNVBAMMKnBraW5p ++dCB0ZXN0IHN1aXRlIENBOyBkbyBub3QgdXNlIG90aGVyd2lzZYIBATALBgNVHQ8E ++BAMCA+gwDAYDVR0TAQH/BAIwADBIBgNVHREEQTA/oD0GBisGAQUCAqAzMDGgDRsL ++S1JCVEVTVC5DT02hIDAeoAMCAQGhFzAVGwZrcmJ0Z3QbC0tSQlRFU1QuQ09NMBIG ++A1UdJQQLMAkGBysGAQUCAwUwDQYJKoZIhvcNAQELBQADggEBABJpKRfoFxyOUp9i ++Z/fWql5anJuZElgBSbEC5sL2mMcmL/1vqkiYF3uF6/Z9g4X1LX4QDuvaXCJSdQ+b ++JpmhklSyFN+E/agxZtSim+AjTgYJ0y+jwNvX6kZQ8fW3VLNJZ+zbb4n4txfgSROn ++7ub+02mo4DYajyD9TE/qLzmVaiKLEKW0osjxX3fB1RN/d7zm//NDPsezzUzmKkgz ++u0ML7HGYUNY3+/SC4ShF/But1IoY3/I46lB6BMrIn9X6fsVKlipqrRFniUk0qDlJ ++fbKVB+MvGEFoqFNlMoGiufmDjnJl4PQZCVEmXO8wAVGeK8NpTBCjltAAsoVJVnjq ++AC5jSAM= + -----END CERTIFICATE----- +diff --git a/src/tests/dejagnu/pkinit-certs/make-certs.sh b/src/tests/dejagnu/pkinit-certs/make-certs.sh +index b82ef6f83..0f07709b0 100755 +--- a/src/tests/dejagnu/pkinit-certs/make-certs.sh ++++ b/src/tests/dejagnu/pkinit-certs/make-certs.sh +@@ -4,7 +4,9 @@ NAMETYPE=1 + KEYSIZE=2048 + DAYS=4000 + REALM=KRBTEST.COM ++LOWREALM=krbtest.com + KRB5_PRINCIPAL_SAN=1.3.6.1.5.2.2 ++KRB5_UPN_SAN=1.3.6.1.4.1.311.20.2.3 + PKINIT_KDC_EKU=1.3.6.1.5.2.3.5 + PKINIT_CLIENT_EKU=1.3.6.1.5.2.3.4 + TLS_SERVER_EKU=1.3.6.1.5.5.7.3.1 +@@ -85,6 +87,30 @@ keyUsage = nonRepudiation,digitalSignature,keyEncipherment,keyAgreement + basicConstraints = critical,CA:FALSE + subjectAltName = otherName:$KRB5_PRINCIPAL_SAN;SEQUENCE:krb5princ_client + extendedKeyUsage = $CLIENT_EKU_LIST ++ ++[exts_upn_client] ++subjectKeyIdentifier = hash ++authorityKeyIdentifier = keyid:always,issuer:always ++keyUsage = nonRepudiation,digitalSignature,keyEncipherment,keyAgreement ++basicConstraints = critical,CA:FALSE ++subjectAltName = otherName:$KRB5_UPN_SAN;UTF8:user@$LOWREALM ++extendedKeyUsage = $CLIENT_EKU_LIST ++ ++[exts_upn2_client] ++subjectKeyIdentifier = hash ++authorityKeyIdentifier = keyid:always,issuer:always ++keyUsage = nonRepudiation,digitalSignature,keyEncipherment,keyAgreement ++basicConstraints = critical,CA:FALSE ++subjectAltName = otherName:$KRB5_UPN_SAN;UTF8:user ++extendedKeyUsage = $CLIENT_EKU_LIST ++ ++[exts_upn3_client] ++subjectKeyIdentifier = hash ++authorityKeyIdentifier = keyid:always,issuer:always ++keyUsage = nonRepudiation,digitalSignature,keyEncipherment,keyAgreement ++basicConstraints = critical,CA:FALSE ++subjectAltName = otherName:$KRB5_UPN_SAN;UTF8:user@$REALM ++extendedKeyUsage = $CLIENT_EKU_LIST + EOF + + # Generate a private key. +@@ -113,5 +139,30 @@ openssl pkcs12 -export -in user.pem -inkey privkey.pem -out user.p12 \ + openssl pkcs12 -export -in user.pem -inkey privkey.pem -out user-enc.p12 \ + -passout pass:encrypted + ++# Generate a client certificate and PKCS#12 bundles with a UPN SAN. ++SUBJECT=user openssl req -config openssl.cnf -new -subj /CN=user \ ++ -key privkey.pem -out user-upn.csr ++SUBJECT=user openssl x509 -extfile openssl.cnf -extensions exts_upn_client \ ++ -set_serial 4 -days $DAYS -req -CA ca.pem -CAkey privkey.pem \ ++ -out user-upn.pem -in user-upn.csr ++openssl pkcs12 -export -in user-upn.pem -inkey privkey.pem -out user-upn.p12 \ ++ -passout pass: ++ ++SUBJECT=user openssl req -config openssl.cnf -new -subj /CN=user \ ++ -key privkey.pem -out user-upn2.csr ++SUBJECT=user openssl x509 -extfile openssl.cnf -extensions exts_upn2_client \ ++ -set_serial 5 -days $DAYS -req -CA ca.pem -CAkey privkey.pem \ ++ -out user-upn2.pem -in user-upn2.csr ++openssl pkcs12 -export -in user-upn2.pem -inkey privkey.pem \ ++ -out user-upn2.p12 -passout pass: ++ ++SUBJECT=user openssl req -config openssl.cnf -new -subj /CN=user \ ++ -key privkey.pem -out user-upn3.csr ++SUBJECT=user openssl x509 -extfile openssl.cnf -extensions exts_upn3_client \ ++ -set_serial 6 -days $DAYS -req -CA ca.pem -CAkey privkey.pem \ ++ -out user-upn3.pem -in user-upn3.csr ++openssl pkcs12 -export -in user-upn3.pem -inkey privkey.pem \ ++ -out user-upn3.p12 -passout pass: ++ + # Clean up. +-rm -f openssl.cnf kdc.csr user.csr ++rm -f openssl.cnf kdc.csr user.csr user-upn.csr user-upn2.csr user-upn3.csr +diff --git a/src/tests/dejagnu/pkinit-certs/privkey-enc.pem b/src/tests/dejagnu/pkinit-certs/privkey-enc.pem +index 9f7816f17..837fd0b01 100644 +--- a/src/tests/dejagnu/pkinit-certs/privkey-enc.pem ++++ b/src/tests/dejagnu/pkinit-certs/privkey-enc.pem +@@ -1,30 +1,30 @@ + -----BEGIN RSA PRIVATE KEY----- + Proc-Type: 4,ENCRYPTED +-DEK-Info: DES-EDE3-CBC,91CA660D6286E453 ++DEK-Info: DES-EDE3-CBC,19FEC334A4D4391D + +-DpJ5bo/AN37NcxTNv0Z4d5YomWqyryqYhuA43FlzWWKubld4Gp+owAv5BUd4VLx7 +-Efq23ODfuiuh5zna/ZXnY+9m8RHS5AxDd2Kr1s/fVsn+m2Lw9qS69DLjxTjEuDLU +-AwmVADqQUbvocZEt0Byn9oY4ku2lGOY/ax7tZ1WegLInnoCqT2xGC6TLw7Gwr3mX +-z6xFB2Yv4PbvVU8y4V+ka0p5manxptYkrbAkC+vrC4LPUACdbonmpeXUxAfVV9hL +-EMzY74IqY2QS1xFMhbLh2HunfjjC3HZ1wXMf1/LtLl1nnodiOk5o+MTLEHO+npaO +-rJn2z3V/eQsr93M8/K5ONQcPAKZGOCmNpNQUj1UHnUHEubhpI+nqRYe3vqem5GaH +-8gn+uc1/N6c/Bs037iSLWvkgk8mvHgH/26JobZ8qg9yYgVUl3AIVkkGwLGhE5+Kn +-593/p4E5Mb6ttv3ZJ4f3Mz/1b84guhTENY67zxnQEGnpEjfRKoEN1vmHi6mIuWld +-rrUCJ/x1Yvy2tN9eyuTNsGCcfvPeY22RrKgl7Wi0EIvBlLPKBQxqXOA7Mi9Acapd +-+n5pW2Ka2FABSifZ36owa7SJEJ0GLMtdHmZPirolgIjOZVOMbSj2UuR/kXVZjZUM +-LcRcVI1z8NgKF3RKs653HqkphcyRQMMQrL/A38t+v0zFA2P3HPoNWcD+BfKg0H37 +-bHPjXdlvAD5yiFXKb1XN99utW5G/qCq5CdzAirm7drxR0bs4ZIV4SwTulvWLW644 +-RYes8x7WKg3WUxtair++c1eTwTPhMLz/SxERYXxSUqpxJiRgYTQhwwbE22P6FCWT +-H9pso5IMi6AJp35CGaYHi78NPLWVmrxgkkv2uBoDFd/iIQTac60aG/F86aozQD7V +-DmHINEcsN3lVUmHinoNTcIfc5EZVEbLQIBhy3XI0UDxWuLnchVlU3ad1OKqknbbi +-Ik3lmeLz07JFbpCcMk+xDlQsZYbxcRzyRh0NsWvHXuG77Hbcrnk3ndxT8wADsfOn +-foXf1/R/gf7PDmte3nFlpEcJCHyeY1haIqgk4WsnUUKP56O75cGF1ylkaBrDPlLw +-WaN2Li537ALo6TyB0jspdCzPqIRt8Gr4muoX0tqFjSfKaWmRb3Y7i6jbVrh8d6KV +-xqLse0Vkaip4Lgf/VUWOTvlfHz9nLD0xR6OUPeQ3jxGdhLxmcYec1oRj1aVMlp6f +-PyC6TN+NlPEtv6KWWB9OMc420DGOWllvS5+zsm7Ff7/5TkXlWmlhfhrkyQVy8NOe +-/3ygPbpSfCFjJMwdbEX+ic/Qjk04f3CluP3FYiIG/Pd6ny6rclrhPHg08X6+sciU +-Rj7QtoFpVsDvde2QO0depdoysAG1j1a+sas2lYNPG8hdzbPe20xIJCmF0fWfdxOy +-BxxtKzpq46S8xKLfxAMvKrZNuZy5xhs3JMUjpxTIam7ZiQXd752LdzGx2s4CII6d +-mkeQ/d32TDACAxyEK8es4Mcm3IoCAq/NjIU/ICwGDeOmfDUpsV2TMrg+aKMKcwUE +-UK4bMXercw7Cs0C3o6mdCTFrTtsihHNTrbb7yyN83XK76niSc+LREbuJ8T0vp1Yh ++S6pSicLj30Jlnu2OnYM0eXCvwAHR3xMhhl2N0gheWUGkjicqTdW6ft1qCmGBre9b ++/aTSF1ajvFC+YQ/iABznWNmRNZKCzTK1dQ6P73p83uNqWt/cfe+pVYdeHw3u8NKA ++fscciBtxnHNaAs16GX5/j1XXRPb+zmUe18A+VFMRgctbaurk+KbxO8qVUkzt9NNa ++v5zHkXnaJf6ixL6zR3cOCJWPGy4GmGeFIytQos5Jgn23Pjn8BHAXf39GMs2n6g5V ++eE5RAGDeXqPv/tO1kN0/RSKDeIPvKW6REklXraRUle0PNN5g5l3umSkg4fkplusp ++nTsQCRWkqyVcMpxcf0wy7F2ZPOYIWDt1/pzAHC7y/fl0uCQPz0Qd1smwt0ABKcZv ++m9zaMq6lkKYnBOxPiYIlWVlQi3RLDiQyAWQz/nF0SKsE88SUlB83quySJsZsLKzk ++MR/C+ccSiHqMiDKVj5Ts1go+gbj8Vhlto8jH6ynQj6lrOIczyMmgUa0v0dFH3i3/ ++WL/8ydJ0otY67A8w5yH3hMzRChXQZlpTmH2dDhAv6EzKBi8eIiB0Em+laz5lDv6C ++SfNxZa1/+bSAvXr7LwllUu+Gzbu7MNLwfB2ieTqdFQGA659DjnMqyBGLFzni4Ir0 ++Hi6Uh6yQubTm07oqyUHAsChGFE4Efh4O0rCbKKPZuSVfimUZcE6JM9IjRC/0DIwr ++LZSYqsFgn44byrc62qV2JAE2ua+/4aHHI28hIZ3MDLwyYpCQL/FAUZtqZvni+zgw ++yoHLRDbdrqPps6P71T6Pw6OQzAYC7AL/FsZnLJK78nI+Yai0dpyv/QWiFSXoDEVN ++6vQoDv/VZbNIctr31OE4XyjIMiTpn3FPa3VSbKM4/h7SthjwEV2ONNfR8XQF+siz ++3NhOjEFrZ6UGHvT06wo/hp4CM7u580fNu5HvyCyIwkx9CZRLHvG6Vu0emlzDfQhE ++qxQs6L7IM8A46/LPSTtmEA8Rrn51YY9NChMdY6j3rLe4NLxxOCE6JYaGWVWBBawK ++k3y9z6L9gWRwxEfCgWIutDrYtmA2aj6y/vRS6LrotCNeN5qBx+TdRnh6uCqbi1T8 ++4rF20TVhNZ/l+pkH/ehY9OJ/zpwdbTq4FlE0wWQZB/vwbYP5CZKF+rU6IXnCZEjt ++Ak6Bka9mFm9Z/TvnKIRYiXELq32zOJAuEOQ576tkDX2rAuIQAfE9biX2qo0gbsJo ++1RIfXekRurD/HX54blv5mNqUV34gl+ngPpV5nNDy7RuTAdP77Mu7/ynaPfnM7nqu ++rECbZVv1HZSgTi+7G9SUjn4Bg36p4NiF0/dZ2W70byYIQvNPNqU1kyeSrZk/43te ++NwFgpoAKVbMD1rZ+0xM2YCFFKQZZMN1a5tn8/1TWPlPU28Tu3ZliGeWMdeKd4/MP ++vfH1pE58qVcyOngjLqGkk0L5A7WOAgu+vibKrxGxywwVLx/GfDFqnNr6H0buwXrk ++vuKBTo0r3pcbaZt3kaYBm0d3zznQI1O/pX+eGiNr/rI86j4KC+jUSoKi4BdUeuDN ++p1x6qyEK37kgVXiUyiEXO7e1arLBZMfFRTNKVsN5ewL441eCIgs5gA== + -----END RSA PRIVATE KEY----- +diff --git a/src/tests/dejagnu/pkinit-certs/privkey.pem b/src/tests/dejagnu/pkinit-certs/privkey.pem +index 1825dec4e..7e9beb09a 100644 +--- a/src/tests/dejagnu/pkinit-certs/privkey.pem ++++ b/src/tests/dejagnu/pkinit-certs/privkey.pem +@@ -1,27 +1,27 @@ + -----BEGIN RSA PRIVATE KEY----- +-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 + -----END RSA PRIVATE KEY----- +diff --git a/src/tests/dejagnu/pkinit-certs/user-enc.p12 b/src/tests/dejagnu/pkinit-certs/user-enc.p12 +index 107480c6d2564a2e60655f29a9984f3009c35a11..049602939def4be1fa9164649b39a801f417e74e 100644 +GIT binary patch +delta 2772 +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 +z%~@S*78!xW^UhVCcK6>Y=Dv}9xW+urfVcc +zu>g#>iAxh_@0-L1`M|BMF|<{62P8z2r?f5+qTVJtpE~#aF(oh~1_>&LNQU0g$6*WuPSm +z)&=BgN#*52!DdM7rK>Tl7p9;qj%3GuXDxAAtu*4h +zC~9=k?MXWaO9t8Iz|oL*2?Un2l9AE|a$=h6Ph7myik>RjLzPAKR~3exF~gXi7EvqW +zE~9J)1$c|Nk0{8hA?+9+)H9)`@X_yoFgT(r4IA^^MTMj{Qg_G_Ecp5%>Z9~6aEq$I +zqZ#8v{eFLJh^yhFyaXX+Wj){=eEmUmy`7~T2J1-8fxBIne8Km2YT>L%0ByK93;aq*c}2&1oN%Xv@sK}hC3l=wcLZg~cO)e4BA +z9A-09@Eafd$`l!^yiLb`C@H8+r5iaEM;12amg^s3a2XC}sPdDEl<$~&v&Pt^O1_1E +zQLtxqpx7ZB63jv2o#cE0mya%atND;ON*P9$5}aRRDv>sZ{ey&Aj(@1u1CJ9R>^DKP +z^ixMkvsI@5PQIVZ3yi;x99d6)uZU8`4H|tVT|k0A07DTdxKdUroElL%G2hIaX>&z- +zGBw+$uCgJ}c49uynU1`N7tso{NI`B)cx`w%*LIVJ;lKpsWLl6f9RZbB1vefXcRoxN +zf`j3p2&6|(LpTdfF`pzIs5HmQw0{t!f-w%I3Vn3;v*=k3Q$aN;z%(z;Q~Gd!!I0h)kqAw}+m +z)+NTjby%K`)VatpY0W8Hew#n^$E=RUK7nr1>4 +z>iwtm%PM>6uO=PfP>m?)-Gb0cP_7gNctp${p3IyR4R=HRqM7Ltg{E|SIaOHhlurhABd(0~x?Wl|2L82IQ(SU$e^JtfBDf7?-BFe^(x+A2}Ar^U?gLKFd_=+-4d3FF@XI)g-zh +z-YtUJqo^N$Ly5y6L8u>qux4^IlnY>!6%dVBhAqwN2zEP8eon_hpqFqKTTU&#sK5}O +zR_G2^6daRk?y%axch8{tVp@I}&7l#{P0Os;!v}UV1h?=i&-X=pfo-qbS+T++W?ZX%Us-H|5<*D)EJXiAg3Bf>mv`pr~(2A00e>r$U;JEGF6`VoCJzVa0|EX +z?r-cm#ze}S%!%psUL4|O7o)w?aL6CUL2C;@kcy;3mXmu9k5552^YysVU|y}Dt4Tre +zPV>~Ox;FGPu3FhmY0ynI1FpBTH20$$M^SakV6_70&$J`Hks;hNehz)Le^GJSJ=_GN +zH*39XikMG#7>%AiDZORRkOLt30;%lzH4I}kR@``X%@4PRBKiA11Q+_vN>vOuEud{H +z&<_ysqjijW)wp?Ok%G6mho{!?zW9O6j+^7LBvOZo|k^lr?BV+&1Np*EvfVARsB<$IWpEwLanuBXis{e8Dk%c%<_`_Vrl+ +zeqkeQsAX_5vbkPxufliV&E|2DwZd +zb0a{R1$ot?e^yQpL#pUx?VWYRLnMsW%7--ugt4*a$I(}Hbu=0C{2_Z-8}s81q&aI9 +zJV$jFX1!0#)!Qr);z4f0ALns&37-$Ja!$6RBT&!xakOnxj9v0?HEOIy+(jna|HALOL6>+lrjgECvKHr!Gf67D>%p^v_`gSa$$4e+m*4;}Ckz#l?vNJZm2-dM=-bp!>L=k|AGKa`?vcIahAIZmTnuxhxl{YICp3 +zbH$qBcKtQZ8KAYVKc9+^HbatsPu{fE0zFaZHYW(`rDO+*{EDYApMIT5Q32n4CqAZ* +z3o$&+QaVdGHLs9Cc0+|GA=Q3D8!`&+u~`8Oe;^^E@Vz;0#P`PM6$qBdZ)?J)lMoT) +zz)rs=&q(e@F^-GlakAu9)f*&p!LhhDMXuDwQi)vur?~mo6w(T +M3X5P3IRXL*0PAOtl>h($ + +diff --git a/src/tests/dejagnu/pkinit-certs/user-upn.p12 b/src/tests/dejagnu/pkinit-certs/user-upn.p12 +new file mode 100644 +index 0000000000000000000000000000000000000000..7a184f651e50d1443e5fe907b5a11455d69bc0d1 +GIT binary patch +literal 2829 +zcmV+o3-a_Zf(r=(0Ru3C3eN@!Duzgg_YDCD0ic2kzyyK{yfA_axG;hRZw3h}hDe6@ +z4FLxRpn?TpFoFeK0s#Opf(2Cu2`Yw2hW8Bt2LUh~1_~;MNQUKrWafC+r24#=H7D;`er=H*b_6X_JS?p@<Xs@2^$asn4KAS;Hr!s53%;M>!4_lI!jE@siDP@6({Y?SkW5h+LdIH$!` +z_-XqxelFC+82Tg$(YW7cLdVydSw%i;-Dj91iRUVJgL03EKjM>L^g{mUmKBVKsyAB4h;T<*EUp~k +z5rfW}jFu*r0k8Y^g;u6zO^A+%O_lMV@d%&03_Kg*X^^o_Uz{`U5MX67$xAr!e22Ui +zNAXN+;wkb+d}b~b&i1*3(p;Exz@ODQOofrIDJ4q$8bvI|QlJ^WxvF6?PHha;kGKy*Lw>`x5`pX#xOpU&t`! +z7)slT|4hs;jt~|+@{`;8_Mdj$GgX1D7bOQ^)Q}w75-Y#V2+pavIB(a*V$3IEP +zg?T;;_;l~R>6v}Ls7>PH|CSU4@((!&99d`8mJ4VP6tfU( +z4xw}bWH@+eq;9;I?L2T^2F%;7KMe9jrkMY5;~yqZdv|HCk0HHe6ELR7-?nEn3P5tpF1(5hLL=IZuz7bA2y^CwDO;azer* +z!C$qO=WhrA@3Sv;JL{~5A4{ohyNZWeqOYnSDSb7#hu$$uU(aKsIIcB?CZ9J;Z5$lu +z=Cjt}MYS&q`XV#P))k%qT34!b_#XJr>cQ`>q`i7hA!{`l0Mcf&{z`~2DbjCAeFaIZ +zsk<_2+ZB>2+Y`;uY#zb8doC4=Dl8MrvwAKUL`Q@5E +znq+%df~WK#qUD~jzbgmfQeAq_dvu$o@tNNmYJPp4oVJ2u0qBUy8Jxcoc2$6Hz}-~z +zxOwJtoxJUF&6R0oar=qp*4XgOz)zgalsD+2B(!V3Q|`x>a-lDmn?dh^U5F1;y2S0+ +zPRYG~!nEeag~ngC@l&LNQUM2ml0v1jyDvT%JrGqHcV|9L||!v`3Xn^r^f=@jKTTw|8IP`5&TRwiQNz +zuxF)@AE&AXjT8}6AiSS|MLo#|aBOswU;hdcU7DWCd`J>wJYfn542DWQmL+e#>?*H8 +zdH;kV9Zz*4#xxQrPTyNZM>hg4EpEgx#nP4#fobQPcfv18grG+nAHI;bL{ylamN8W@ +zKljh2Bb-jW^J?a^CKm+huNYxBjL<&hBZIF2SK +zVu{~Wpo9P=Pg;QoJ|*nw7DjGB4y_W^t4=uyCXy=!hMY3cGj*tx`I>011gj_pl(O=FX4%Pv8{?*qOk9 +ziMJ9kiDb%Rq~);boeQ_o6Gz>K3&BxCt+`@~nJAh%g!EqIPY9B0ewTqT;whOBDJtl59yda9Br}TXCfgC9#E~QjpuTlPa3D;Kuf{=3 +zeP!#*-6{&>E_LrM8`cuctXs|W@67%V=)pB@oy&Yus +z@2ph_mT_Bq{2J2QMk74-EEJMTAE*X9x#e!==1 +zfh0RBMQN77*2GhWj_q=-;Wz;n_ig?}US0W`OuQS?@DtZzW1f~nnyoPy(0Hx*GdchzpbQ0S0ir-J +zuHsr4irnU(ilPifZg3UpkOD}qmij*p0LDWB`u7D|00oR5NcER_L2r?C?;0s76-g9| +zoP$#^&~mk2OIS|=F_sMsnX8)@2#;-@M`*t=Bh1+Frmnm8t#fylmKL=Kk92~}LueGYkFoKdBM+&*L7DFr$HNMR#9xE?N?M^FnQZJ^OT}z~im)IwW1caxhYM;+?)l +z6FfS#9Zi+;8|~jLBE|RqTDAHS-Es(u*=ip2^4OkHCUs}hqma-3PAVfv2kYkUh7$_j +z2|o2WEq=(;OC)Sg0{2i&3wkEy+s&cco^Hy?ow{G9!#<1CX=U-w;l%M;QxsMc1X{6^ +z@6*5A?zKfo@cDpT+L%OfWgny?;`z+SIpl0Bg=fDrrRB=EaGDD+ODlERhx_l4t_MSA +zZ`6*wF0gJrmlz&9>PSWsZRGWzM9)1?B%hhQDZaPZz)@56+a=hTJ^Gd+X{KWGzD#mq +z-)pP0)q9px96kY?$-{@ArN#H3W~b5SQpD^r{( +zR2Aa>s|ul_3wCEtZPXyZ-^r|UbeSu}@3Tf;uCGgUPxvsJ_f8btP9L)4Gg}HiY);_2 +z+mOZkK=xZm%YI+y7HzaRSCY`jya)D=X|9p +z4i<_VEkh~=A|CY!+4#xR43GCR3n_n$#mB!Q*Caq98D{#S +zG2G6Qx>5L(CX1A+juY-*fdn6FiaFyDIVxdbcL^V(xEaKTCEGE?Eg-?Ir|*F}s^5!F +z?uPI=y0M>KgdCNtoMqO7WN&7|%urZN+YeMK2xf3r~lQ+GSa7%(FHQyBM;pW9P% +zaYm6(pg&99#xo>+!=(tb&Z%7-db}vcu*5eLkNkGZo +zzF*Fi3O>s*3bhY!SM}Vz^#%)mEr-e%Q@4;7yibf%Z7JO1P^k=rogOwEP53EasxnaeY|& +z@#_1`qn`I>sO}W|rUxMujvfdt)Pw>>jdIQ$6rBk!R?Dt3>HE(ioW+$zbs`si)M<^v +zD!WD8%JztN8Hd@%EZTZYNj~AzLgM)N-?t%C&ch~aytdUXOx4wsy9c5Nt&-Emq#f4- +zHl=P`cgVJINMbU#Kdm%;UPucqJ=;5x2HOrGV*FpO|#t8^HM1;b*9+* +z?Zrj8WYTa5?5X87{AmuhQ~{eUOrUJ)e#{c2RMvjrL*+(0axNW{6}k4rWO^+1h+8G`-UW2$QEGKUu2I^6J46a;(RUNp$Kxxh+7_@dXK +zD3E6J{uf}Muo{~}jVZQ{9-6OTAubq-@rVmDa-`b|`7@B!AeO10305~@Dr%6}iV8CQ +zX=X6;)T_SAFS7M$LiE@D+*=b7TUtKh#SiDT!#~CG=`dm~xS(|WMh2cwC +z9xApaX8)-#y$}a)r)<27$PL=Btmpkt47*NBvk8ah#FF41>VQUrT~(jsda)wttvb!- +zM+f8nK~3)SE8Uzv>G&lV4)_-4`%LMHreSl%ftOL3EVsbU&-o^)j+>LMjzQhwIHkzs +zj3_$2&5jM8($vnfB%~s(`|}Z1C!?xTVII!4JlFJ1^Re_w@F9G4mN$!!_KgcobwEi=6Y(|7ZRIDRJGT*_~94IW0yH%-kFs9feQJ1yJn96nt$lA +zzrxgdtPW^+9dj6s89v$x=KzGEryP`-O_BZ+GS2{l%GJ +z;Wg}AbQUBB4M?CzGy8Ssk9A|Hpi;6b7mn2$y?*zP>|QNHc|A(7fn(<1Cf>^n=D2i4 +zKzgEcD}!8bkWoA}X|O@i)yfYB<*)NprS!O-sZn>>{Fs%#IjfvVXcK`c!w>TZC_`)L +z+iDpL1H%ga{1M#fkH5W(UbJ6AdC5@ +zU_?h2EWjXR{7@lx`=c0sVEQ~^7P$v3nigDDUJKG8QvK%lSC^!oJ2OHT0o?DE{uPC?#3C(OA +zki6%DF9nBN!6h`eVtXs4W(A%(^dA#v!!&+b>kELYWpRq53rJne*K(ZpG~HB_^VCt? +zf}PYa%M7*9wP4L>v+TwLKvTK5;tbtW_0s`(G_#F47O@y)BStu}uBOf)QBy-Z*`=tIAm?i4u#!!!3KB7)I +z&S&h+XZ9MjAMs0e`O9!!0W;w!w{oKJ5c?VTVfMz1gdptZe|4k=ORxc1k(BTT-5~lg +z`SxY-DooVB&XB_ZCIRDzQB#oLrY9riA}0Z|8jeaL!SN1ZPMJZ5zHE}mPLR8nKq_{_ +NjEEGCzWl$H{1*d>HH`oO + +literal 0 +HcmV?d00001 + +diff --git a/src/tests/dejagnu/pkinit-certs/user-upn2.pem b/src/tests/dejagnu/pkinit-certs/user-upn2.pem +new file mode 100644 +index 000000000..3a5094c84 +--- /dev/null ++++ b/src/tests/dejagnu/pkinit-certs/user-upn2.pem +@@ -0,0 +1,28 @@ ++-----BEGIN CERTIFICATE----- ++MIIEuTCCA6GgAwIBAgIBBTANBgkqhkiG9w0BAQsFADCBpzELMAkGA1UEBhMCVVMx ++FjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxEjAQBgNVBAcMCUNhbWJyaWRnZTEMMAoG ++A1UECgwDTUlUMSkwJwYDVQQLDCBJbnNlY3VyZSBQS0lOSVQgS2VyYmVyb3MgdGVz ++dCBDQTEzMDEGA1UEAwwqcGtpbml0IHRlc3Qgc3VpdGUgQ0E7IGRvIG5vdCB1c2Ug ++b3RoZXJ3aXNlMB4XDTE2MTIxMjE0NDYzOVoXDTI3MTEyNTE0NDYzOVowSjELMAkG ++A1UEBhMCVVMxFjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxFDASBgNVBAoMC0tSQlRF ++U1QuQ09NMQ0wCwYDVQQDDAR1c2VyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB ++CgKCAQEA05a9cPK5tn8p/xBh09JGT+uyiDOpLSvJw0Qmn/qs+lNLjRTEZp7kzIsd +++Y2XaZJ69GgdKqFvtx9Pqf2RHaRvccHSqGGF5wd7LiwbB36btYyEFCBW1hqJaS4R ++AMLv9JaRFjOZhfwnjW+tC6VdTb/ak5AKYbg0o+w2j69wqhPZIeXqqveV+VRogbTA ++O7hsWtazOTFy5KRTtJJcN/bFNNMnxB+07pZBjeDT50CFuNkUrFE7m6KnFRF7PkR6 ++ZWxF7zq9cQguRrzm2JVLiZoKfeXcVYypwEdEU1r7+ixNvQn86a+91DdvO+xwbsoN ++G0xtFSelYKWvlH4BsZW8qhyPkjX4bQIDAQABo4IBSjCCAUYwHQYDVR0OBBYEFGvA ++yQ58yg3eh+Oi1JaMrRzbt9hiMIHUBgNVHSMEgcwwgcmAFGvAyQ58yg3eh+Oi1JaM ++rRzbt9hioYGtpIGqMIGnMQswCQYDVQQGEwJVUzEWMBQGA1UECAwNTWFzc2FjaHVz ++ZXR0czESMBAGA1UEBwwJQ2FtYnJpZGdlMQwwCgYDVQQKDANNSVQxKTAnBgNVBAsM ++IEluc2VjdXJlIFBLSU5JVCBLZXJiZXJvcyB0ZXN0IENBMTMwMQYDVQQDDCpwa2lu ++aXQgdGVzdCBzdWl0ZSBDQTsgZG8gbm90IHVzZSBvdGhlcndpc2WCAQEwCwYDVR0P ++BAQDAgPoMAwGA1UdEwEB/wQCMAAwHwYDVR0RBBgwFqAUBgorBgEEAYI3FAIDoAYM ++BHVzZXIwEgYDVR0lBAswCQYHKwYBBQIDBDANBgkqhkiG9w0BAQsFAAOCAQEAElYM ++786mUr91z82s6QC0TwP380ze8yJQiaWifHYXiqIPay19M+QG91PvSm7LLZw+ersC ++gEl/mPKrC89XlAFp8b+hJnGq6t6YmeC7OI+FapEMxpxX/X8eqAOQLrGnoq7Pm9/8 ++QtWaKgo09i7rmyykKl3xSU1VktBsmlhNPPNh3x+N4bxea9OIbZonPdDtr5/Yt87/ ++6kBPsGgvUUoIxLw03OmLu8AmKAwJja0FWyu93uCUP4UZWLEGpUhSYC1uUCpAZDNy ++2AtPnxfGUDtvI9eMmyeXVGYXTfkfGZyvB3m9lyIj3VVmhbvr7qLAGQn00dbOHz16 ++r6w2aye0Me0GcU0grg== ++-----END CERTIFICATE----- +diff --git a/src/tests/dejagnu/pkinit-certs/user-upn3.csr b/src/tests/dejagnu/pkinit-certs/user-upn3.csr +new file mode 100644 +index 000000000..958c1e043 +--- /dev/null ++++ b/src/tests/dejagnu/pkinit-certs/user-upn3.csr +@@ -0,0 +1,16 @@ ++-----BEGIN CERTIFICATE REQUEST----- ++MIICjzCCAXcCAQAwSjELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDU1hc3NhY2h1c2V0 ++dHMxFDASBgNVBAoMC0tSQlRFU1QuQ09NMQ0wCwYDVQQDDAR1c2VyMIIBIjANBgkq ++hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA05a9cPK5tn8p/xBh09JGT+uyiDOpLSvJ ++w0Qmn/qs+lNLjRTEZp7kzIsd+Y2XaZJ69GgdKqFvtx9Pqf2RHaRvccHSqGGF5wd7 ++LiwbB36btYyEFCBW1hqJaS4RAMLv9JaRFjOZhfwnjW+tC6VdTb/ak5AKYbg0o+w2 ++j69wqhPZIeXqqveV+VRogbTAO7hsWtazOTFy5KRTtJJcN/bFNNMnxB+07pZBjeDT ++50CFuNkUrFE7m6KnFRF7PkR6ZWxF7zq9cQguRrzm2JVLiZoKfeXcVYypwEdEU1r7 +++ixNvQn86a+91DdvO+xwbsoNG0xtFSelYKWvlH4BsZW8qhyPkjX4bQIDAQABoAAw ++DQYJKoZIhvcNAQELBQADggEBAEMxNp5md+jV5dFC1iSKh2CYl3P4g3UMQ9NjLcyq ++upjJmFiEGkEg/LpH4CoXI03BaD885S7akKPA1J/sG2YIrbl3TpjUJKZoJ8BjNT0L ++tYc+JIODZJEONR34Fh6/1uRU7UkRcJ8Crc83+ML+71O2SRZRJDEOS3tVbdzjEOTj ++HIed6Ia3cu0XeAvhoqRSjh8J0ufoIv3CRRCtRU8ChkmMD64p3kOTlORxWspAF8sm ++Xa53bWIpyuyz/vWwpWfr+fL+Q+BQ1TU39xvy+46AYuQIIKzK9vKZdCElQwFXZs26 ++f53OyZpFjcsT9jJAM54XUxLv5rE3fqZQiBhatPZa2ThHt08= ++-----END CERTIFICATE REQUEST----- +diff --git a/src/tests/dejagnu/pkinit-certs/user-upn3.p12 b/src/tests/dejagnu/pkinit-certs/user-upn3.p12 +new file mode 100644 +index 0000000000000000000000000000000000000000..a9d4780c47d33cd4d409d6ee657a7911381fe753 +GIT binary patch +literal 2829 +zcmV+o3-a_Zf(r=(0Ru3C3eN@!Duzgg_YDCD0ic2kzyyK{yfA_axG;hRZw3h}hDe6@ +z4FLxRpn?TpFoFeK0s#Opf(2Cu2`Yw2hW8Bt2LUh~1_~;MNQU4cR+h_S!1xwTJB>WLrfC_;4Q{WSMU*o- +zn@1qFp2kU-SDex#I*!6h8=!K8qv9pObzLDLmnzWdibwhCfJuy%lF%>17?*+`lBBJM +zmXpRI{I$vJ#9ra!;LI(a-Y;XQ;Lg(@=%$W%N@M`uG=dT?Us_5#Ydy@oR}Jqosz*ey +zVPGvYS6-Lg5~d9q+Kq_7hwvb*@x0}_hvi{GII8!JaJ+M3rIu;J>8y>3=gG`dH0^iR +z|2dL^4OS11LK|#C4SCTCdZoH|NY!h^jRkR_ZBdMalelZlJG~EQsb631B6Pems-P<2 +zy=ikP`PqC(+TZsM6awppC_f0Xl3g4K3t|VAQ*|@tqWP;7pCfxOI}DZ9(iJy)rS*nL +z8a}#DV!e3{QR4jj(Ty7a7d86H_%`o3)tY*5-w|QkembO|Ujs3}!86C73mgV0q^5iP +zuZU!CsXRr9j$1G307B=@uSo~fVS&hEIJ+>AH&cjQ2XBCfI;BM))U5*2LLkNN(0?0u`ndx|WU+*&cfWKL8;~Qf+dr$yMp*|3(UJ$X~0n_~&n<|bR +zOiCnb3@;b`fsYZW;zy3u!xk;pHehyodmHBK(b4`FY+RdV=I@k+phXazTua8A-KghY +zbHI;PA;HtNCqk1?WmxDfVMr;cPF-ev6fv2Fqj2|J6VMXUHxmH&PN +z7i%{(&ibQjorX+L&72F>74o;aDdTY|SfNampj*cW`)4?RC{QhRV~@au<4#(Y1RTbE +z+4)2+UV+lnFK&q(3AJu`R~b$_-o!)-dXZdz3uyEXkjR$GQ+@~Nrzj3Op78qsDTByr +z87^>(n=t}k--9Y2&($W_V$rpuB>QO?+3-dA-pr3g54LFhpSdbUZ|IdewW&nX@Id-7N;;8dTYiF$bj&+Vz +zp+$O4o`v}qtLqJumEjK!5TYC+&IxPxnPJ?qPwid3z%qigSZUd*O)r-j4oE29GsC=< +zw0myiDI9d*4E>t?xOcwEA~EKL0)VbEj&Uc^xro!On)Pjn$+w5R6#oT#|93jg*@V}Z +zk%j`((IQj&TOx`1Bp_153n75Eqw3)xRNoBq49xGry~PpA>RD@*p=h}-LFRPD=V~%O +zL!t(9?TCJvy{&-ipV)bfua3YR-|1T`d;?f_6b0}I+QRRVRCX;HVm@R2;PE+7K +z3Q|#cnBp2{Ho#|+7-NPyucnCX#eD8mEc6JWn6yVrPT1jqs)!%NzfUi>O@f`DTz7r- +zs6~@+cMQii)Zyfm5|I-1^j4{K7>B7|irNe8d;&TQyncnqec(ERvcvZ=HhwevKN)GU +zzDKIn4gl?ZdnRwvb(WT2#ZBk3!kjVDJEGu3Mj^N{FoFd^1_>&LNQU?&x>nfj%n^6>^V7CUp+ +zETM}jN%cj-MzspiSpQ6CYmqrq{b{-|Kj>-Fd1TKY;L3MOk&IO)fs00$bk5ZHGFaBf +zsRg6kCS^21bh?tWf1jQLIaT&uM>-1!L@?~)eWqce&iDF0qMSy`TNzT_)VB-&hdVeW +zjEeXb0i{%KpZeK!$PY01Wa=BLfB6xzk$J9wnQ+$8Q?cOhQWJ^oEshJdhCpbB9?+gW +z%#d0mHXCu4Kr$r>M+VFC+yRsa^lQ^YyqVejN5NolmXwl=j;AXtkvzSNzYdLcLS1M3v(LEqdCXAG^SL1Jy92cADy`hRveJZ&>9tO3Rq_n_U2brOPWo6XM +zre^&}huWluk$ +z+B?xm6(8=jJ-w!B_8@+OFo>mq_>DV#ryewM9%Z)!#3=XxhO#WL%G$~t4CS!5WVoB@ +z9IwU{Qb#y?ADZ8(K#I6quZz_TTCR&i8M?`ng1<++_9q(O>U=r;A$ep&O5PL~0ADX*&QcF)J*1tw=!Jp;oWW92 +zx_WL`bX!>KW=&X!8je^w5L8BljVzqd+B6(1iYw*+a2t*Og-{}@ahG~CSZjlKgN)_F +z_gX^4sG +z?|whq1p%Fu)%2@m@;098MdnS5un)e;6`RgFr)yc~xn2wcd|aAZWeZIH?b=2rqMuuF +zhM;R=1L3DiNIjP$4H_N4*lqU$eq7|>Ys3|ew5^EImFF1cx!T2jaX +zfyvmtstS0orV!Q7PL#g{*$ChxfS!0s;sCZ%;ud + +literal 0 +HcmV?d00001 + +diff --git a/src/tests/dejagnu/pkinit-certs/user-upn3.pem b/src/tests/dejagnu/pkinit-certs/user-upn3.pem +new file mode 100644 +index 000000000..ffedb0d1a +--- /dev/null ++++ b/src/tests/dejagnu/pkinit-certs/user-upn3.pem +@@ -0,0 +1,28 @@ ++-----BEGIN CERTIFICATE----- ++MIIExTCCA62gAwIBAgIBBjANBgkqhkiG9w0BAQsFADCBpzELMAkGA1UEBhMCVVMx ++FjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxEjAQBgNVBAcMCUNhbWJyaWRnZTEMMAoG ++A1UECgwDTUlUMSkwJwYDVQQLDCBJbnNlY3VyZSBQS0lOSVQgS2VyYmVyb3MgdGVz ++dCBDQTEzMDEGA1UEAwwqcGtpbml0IHRlc3Qgc3VpdGUgQ0E7IGRvIG5vdCB1c2Ug ++b3RoZXJ3aXNlMB4XDTE2MTIxMjE0NDYzOVoXDTI3MTEyNTE0NDYzOVowSjELMAkG ++A1UEBhMCVVMxFjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxFDASBgNVBAoMC0tSQlRF ++U1QuQ09NMQ0wCwYDVQQDDAR1c2VyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB ++CgKCAQEA05a9cPK5tn8p/xBh09JGT+uyiDOpLSvJw0Qmn/qs+lNLjRTEZp7kzIsd +++Y2XaZJ69GgdKqFvtx9Pqf2RHaRvccHSqGGF5wd7LiwbB36btYyEFCBW1hqJaS4R ++AMLv9JaRFjOZhfwnjW+tC6VdTb/ak5AKYbg0o+w2j69wqhPZIeXqqveV+VRogbTA ++O7hsWtazOTFy5KRTtJJcN/bFNNMnxB+07pZBjeDT50CFuNkUrFE7m6KnFRF7PkR6 ++ZWxF7zq9cQguRrzm2JVLiZoKfeXcVYypwEdEU1r7+ixNvQn86a+91DdvO+xwbsoN ++G0xtFSelYKWvlH4BsZW8qhyPkjX4bQIDAQABo4IBVjCCAVIwHQYDVR0OBBYEFGvA ++yQ58yg3eh+Oi1JaMrRzbt9hiMIHUBgNVHSMEgcwwgcmAFGvAyQ58yg3eh+Oi1JaM ++rRzbt9hioYGtpIGqMIGnMQswCQYDVQQGEwJVUzEWMBQGA1UECAwNTWFzc2FjaHVz ++ZXR0czESMBAGA1UEBwwJQ2FtYnJpZGdlMQwwCgYDVQQKDANNSVQxKTAnBgNVBAsM ++IEluc2VjdXJlIFBLSU5JVCBLZXJiZXJvcyB0ZXN0IENBMTMwMQYDVQQDDCpwa2lu ++aXQgdGVzdCBzdWl0ZSBDQTsgZG8gbm90IHVzZSBvdGhlcndpc2WCAQEwCwYDVR0P ++BAQDAgPoMAwGA1UdEwEB/wQCMAAwKwYDVR0RBCQwIqAgBgorBgEEAYI3FAIDoBIM ++EHVzZXJAS1JCVEVTVC5DT00wEgYDVR0lBAswCQYHKwYBBQIDBDANBgkqhkiG9w0B ++AQsFAAOCAQEARVeLPouequn86P3LgOZQ9LpP6IHpY2ZQwvNviiA8Zk0hsqFXnmwx ++wr3JtESim3EPuwQtJ3jXp0rxQB02r5r8sg21OjCeAB+vOz3IoF/y6WEYlz67LjMB ++XCB6Fuq80IHhVXWRi7w8dVI8xcADwIOh6fgzwbbk8qV2Lgn2Giivstp+76PnRtEn ++tavWlWW7bQlXkiROYh6u3Y8IvYYoIdlDsXQBFSRE80Rc2jR2XGKAz5CDEZNC7RAH ++Z7ON9HH6IRBOX1ijmXhBl/39QQ5t+ZYgKk8OJpL1RAZlJZtGMBwJtA1aGiAFvqTr ++aCREHZfn9NAFE/szItH7hxWJv9RISUXYmA== ++-----END CERTIFICATE----- +diff --git a/src/tests/dejagnu/pkinit-certs/user.p12 b/src/tests/dejagnu/pkinit-certs/user.p12 +index a7c2baddf67f5a8c6ad97b661f6ff285ecd5bf37..67c3fa2eb01c9fdd543af9172dc63a3955987ed6 100644 +GIT binary patch +delta 2825 +zcmV+k3-L2N;;rqK +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 +by5{;I{o2EAUPuH8o2f}+U#knW0s;sCTvk7E + +delta 3072 +zcmV+b4FB_$7N8hFFoFym0s#Xsf(zmX2`Yw2hW8Bt2LYgh3)2LG3(qiu3(GKq244mV +zDuzgg_YDCD2B3llP%wf9OacJ_FoFg}kw6`P!$C#iY;oVd0s;sCfPw}X{k^@yX8+%9 +zwBJ}5flvw?@^UAz@E_15;f|7 +z%=`IEmu8Fm{;M@9J1*`p_pIcRPLK(+FMWn?4Ww%T0x^GtUpOaX{(}d=6zfxU*O_P_ +z;{8-Vz=+PJ*fq5Q5}1P|h8#+LByXQ+P>3e*vahmych~z9*bcGZU>fX`OHPSi?VqiC +zB=Rqvb+r)J90J&GI+Fao+TB6@Z9^%48aMh$*5ZZ;bg}FUG;4;3aF(v8Mc%?$$0qwd +zc3^N%>ETq(6vTI$`2w_1OaX?h#=Tof#*z5MeSw0*v$CMQcQ$S>moyee?d|Ygd +zOSrQGiK>X-ozcDa;*JHQLCC}?$LH>?!Yi#hRsnX1OX +z*EB3%Xa}bdITw;zI$pm5MeS#lApv12PFz^)>i>;Kq;rwfsX%C~f|;W&4uX`4^{hYr=Sv0%nHrgoVxp@+Oa2pz6_!d%FIr;pRDqUYfO{2<~UWQ(O#?)HAW1rbVG%r +zq9bBAoA9db8X#}@U%8%J7?%N|4`BO{Kf`A)Bo>s1w3U?&wtbya#nq(}in*aOqVWwL +z54v^FBkaQkJ{{9QU=Swu92Ip%GvLLOIDd7VZmIBi##hu?f(v78%UHjEu7or)#XQ(K +z6nwxUcCasL?i8)8F(v3tkFjU0@B||ae%?*I6IKzV$B;Xlklq^f`Sg6cXaqJHeeaB= +zR|Kl&E3F1db<1&_nuDc1V^iiCJ{=(AE^+aqY5NBcI$5;qni~17mHn5(Ds))Qj>(fB +z!cAhp`uQ=F+SOD%%+Ha38w{~j +zo9@HR2C2O8b?-H5VC5*x&5I%i_u7WWj~_7^J#l4mNU^ZX$|TykZ>kn^P>m*4do=8) +z-lvs7RD7|XX;o@sWC$=qUP|t9tI!D(6aWp9r+d%S@i=hsUzZGj4`0ajob3mf39g=O +z%sLUXQul@047pG(XAo^Bzg#aTGeIP9XG%lsySCBt^BD;L!P?o>8|72>-F%bY1Wq+- +zQ&co>uVf4#KdH09JZl->qdH!j&5obWpC252k*~RRm`++aA +zb)ix=M5o +zkDSS^SpDZ46j6?8FSSEt!hzU2{_KAgGG#C6JOuiZ$dBlrIHJI>a!|_ci}n~u6wfBn +z1&}v(3R~EJEM#g)ZxZO$;#Uy*l%8e6KIeQxo6!Ev!p)g^jmB_%6GXqkLS>=3J;!BiP~zMs^7_ZV@z2e~h;XLQo=1(w3< +zKSrEW)`6L0#?Y=Y^OVjAPol3~Y2-UA_>BjuU<55l@tHF|>M7Zh5YYg$$Med8J1xt2 +zLP*MiFoFeS1_>&LNQUQ6J*E3t0>aCid|=?nFOo@xF7nMEwFSqGFL=q6+5@%_ +zt-z3k=H;LP>M5^($OYSZJ{(r}tFwIj +zvW>%k6&+&B`~)0-Gg;CuKJ}d10CU^>UaG3Eag)cBnkgpw6c$vz5a->`qeYY{qOzjV +z$lM&d7YnfSl+TL;$Z%XYD8P&u6+OPseP8BbQ`Co+4qNH^w^HP@t~i7h`yya}!u<oz#o;ZUj=Hp +z(TV68ifC2(4C2=wv3r~1104(jA4cs9gd=F=kJAOeb?#j`oJ0bKe65FiHPEx{!4^2M +zz^<`>c3WJhEzhxX)l8^flHtnoU_1>9oCV*rdmGdTgN`7ewco2nZuA--|EL=EaG4Nn +zpF~eT3tG2-f{+uROTHXdk{V0)X{9@F4mpkfDP7mjH8Tej5p$_wAOlRUsVV8eC0hd` +zl4Cv#L%OnpO;^-jK=n`BoqWJ#I2zzYA;sz+Y;icw<{th3N}p#_Xrp8*rEd6NEX=4@Qp-i%c1jGY-l^{T#gMCnLtFM}iUj!H}kK_5;CTggujzqx``SqC!?Fq@kO^ab0Yk*7|TX+l3@A8Z-brb&{t +zZX^wVHoyg=NeF)1EnnZ8*NrQU!QHwFx6a1u4+j8i75XaX{V` +zTejP79{ii}hnRQ)sO)7qj>Pd@U}lVl&(b}Ag$oc4za4|Y2`)pu(3@Q{oocgpL9XPg +z&ARc&g{ZqR#9lsFPr=r@2fK*A|lb4n3k%R8?I#c2D +z;=TTZZ*j*ygj57wLl>LICIh&x-2VrAPjpHqNvA6BWcuW0J`V>k +zX2DR;M<%0M5rj)YL!vo}Lr8*yNjn|jEon4LP>F3;n-~NKB>zj8a%?p*fZm_SEdJB6 +zP-Yt1+4};5@fwomsJaS~^N?NR6BXot?2jw}Jgj_7AnKjnZoO5nIY`wuDf(}pQfmod +zE}t2${x!MEq*UT6S13ie-bH%m!2V*Ai?V#!PB*W9mXC+U>&7FB$YbjRT!@-#?o3x& +ziB>ytwV(g|m}&0NES6Y|(~D_kcv$pTt6{{O5=Tjd*U#!Tli@}SuFK6QcZ9`%x3jAa +z9wib(pG>woZhqj$pub +Date: Wed, 4 Jan 2017 11:33:57 -0500 +Subject: [PATCH] Deindent crypto_retrieve_X509_sans() + +Fix some long lines in crypto_retrieve_X509_sans() by returning early +if X509_get_ext_by_NID() returns a negative result. Also ensure that +return parameters are always initialized. + +(cherry picked from commit c6b772523db9d7791ee1c56eb512c4626556a4e7) +--- + src/plugins/preauth/pkinit/pkinit_crypto_openssl.c | 224 +++++++++++---------- + 1 file changed, 114 insertions(+), 110 deletions(-) + +diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +index bc6e7662e..8def8c542 100644 +--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c ++++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +@@ -2101,11 +2101,21 @@ crypto_retrieve_X509_sans(krb5_context context, + { + krb5_error_code retval = EINVAL; + char buf[DN_BUF_LEN]; +- int p = 0, u = 0, d = 0, l; ++ int p = 0, u = 0, d = 0, ret = 0, l; + krb5_principal *princs = NULL; + krb5_principal *upns = NULL; + unsigned char **dnss = NULL; +- unsigned int i, num_found = 0; ++ unsigned int i, num_found = 0, num_sans = 0; ++ X509_EXTENSION *ext = NULL; ++ GENERAL_NAMES *ialt = NULL; ++ GENERAL_NAME *gen = NULL; ++ ++ if (princs_ret != NULL) ++ *princs_ret = NULL; ++ if (upn_ret != NULL) ++ *upn_ret = NULL; ++ if (dns_ret != NULL) ++ *dns_ret = NULL; + + if (princs_ret == NULL && upn_ret == NULL && dns_ret == NULL) { + pkiDebug("%s: nowhere to return any values!\n", __FUNCTION__); +@@ -2121,118 +2131,112 @@ crypto_retrieve_X509_sans(krb5_context context, + buf, sizeof(buf)); + pkiDebug("%s: looking for SANs in cert = %s\n", __FUNCTION__, buf); + +- if ((l = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1)) >= 0) { +- X509_EXTENSION *ext = NULL; +- GENERAL_NAMES *ialt = NULL; +- GENERAL_NAME *gen = NULL; +- int ret = 0; +- unsigned int num_sans = 0; ++ l = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1); ++ if (l < 0) ++ return 0; + +- if (!(ext = X509_get_ext(cert, l)) || !(ialt = X509V3_EXT_d2i(ext))) { +- pkiDebug("%s: found no subject alt name extensions\n", +- __FUNCTION__); ++ if (!(ext = X509_get_ext(cert, l)) || !(ialt = X509V3_EXT_d2i(ext))) { ++ pkiDebug("%s: found no subject alt name extensions\n", __FUNCTION__); ++ goto cleanup; ++ } ++ num_sans = sk_GENERAL_NAME_num(ialt); ++ ++ pkiDebug("%s: found %d subject alt name extension(s)\n", __FUNCTION__, ++ num_sans); ++ ++ /* OK, we're likely returning something. Allocate return values */ ++ if (princs_ret != NULL) { ++ princs = calloc(num_sans + 1, sizeof(krb5_principal)); ++ if (princs == NULL) { ++ retval = ENOMEM; + goto cleanup; + } +- num_sans = sk_GENERAL_NAME_num(ialt); +- +- pkiDebug("%s: found %d subject alt name extension(s)\n", +- __FUNCTION__, num_sans); +- +- /* OK, we're likely returning something. Allocate return values */ +- if (princs_ret != NULL) { +- princs = calloc(num_sans + 1, sizeof(krb5_principal)); +- if (princs == NULL) { +- retval = ENOMEM; +- goto cleanup; +- } +- } +- if (upn_ret != NULL) { +- upns = calloc(num_sans + 1, sizeof(krb5_principal)); +- if (upns == NULL) { +- retval = ENOMEM; +- goto cleanup; +- } +- } +- if (dns_ret != NULL) { +- dnss = calloc(num_sans + 1, sizeof(*dnss)); +- if (dnss == NULL) { +- retval = ENOMEM; +- goto cleanup; +- } +- } +- +- for (i = 0; i < num_sans; i++) { +- krb5_data name = { 0, 0, NULL }; +- +- gen = sk_GENERAL_NAME_value(ialt, i); +- switch (gen->type) { +- case GEN_OTHERNAME: +- name.length = gen->d.otherName->value->value.sequence->length; +- name.data = (char *)gen->d.otherName->value->value.sequence->data; +- if (princs != NULL +- && OBJ_cmp(plgctx->id_pkinit_san, +- gen->d.otherName->type_id) == 0) { +-#ifdef DEBUG_ASN1 +- print_buffer_bin((unsigned char *)name.data, name.length, +- "/tmp/pkinit_san"); +-#endif +- ret = k5int_decode_krb5_principal_name(&name, &princs[p]); +- if (ret) { +- pkiDebug("%s: failed decoding pkinit san value\n", +- __FUNCTION__); +- } else { +- p++; +- num_found++; +- } +- } else if (upns != NULL +- && OBJ_cmp(plgctx->id_ms_san_upn, +- gen->d.otherName->type_id) == 0) { +- /* Prevent abuse of embedded null characters. */ +- if (memchr(name.data, '\0', name.length)) +- break; +- ret = krb5_parse_name_flags(context, name.data, +- KRB5_PRINCIPAL_PARSE_ENTERPRISE, +- &upns[u]); +- if (ret) { +- pkiDebug("%s: failed parsing ms-upn san value\n", +- __FUNCTION__); +- } else { +- u++; +- num_found++; +- } +- } else { +- pkiDebug("%s: unrecognized othername oid in SAN\n", +- __FUNCTION__); +- continue; +- } +- +- break; +- case GEN_DNS: +- if (dnss != NULL) { +- /* Prevent abuse of embedded null characters. */ +- if (memchr(gen->d.dNSName->data, '\0', +- gen->d.dNSName->length)) +- break; +- pkiDebug("%s: found dns name = %s\n", +- __FUNCTION__, gen->d.dNSName->data); +- dnss[d] = (unsigned char *) +- strdup((char *)gen->d.dNSName->data); +- if (dnss[d] == NULL) { +- pkiDebug("%s: failed to duplicate dns name\n", +- __FUNCTION__); +- } else { +- d++; +- num_found++; +- } +- } +- break; +- default: +- pkiDebug("%s: SAN type = %d expecting %d\n", +- __FUNCTION__, gen->type, GEN_OTHERNAME); +- } +- } +- sk_GENERAL_NAME_pop_free(ialt, GENERAL_NAME_free); + } ++ if (upn_ret != NULL) { ++ upns = calloc(num_sans + 1, sizeof(krb5_principal)); ++ if (upns == NULL) { ++ retval = ENOMEM; ++ goto cleanup; ++ } ++ } ++ if (dns_ret != NULL) { ++ dnss = calloc(num_sans + 1, sizeof(*dnss)); ++ if (dnss == NULL) { ++ retval = ENOMEM; ++ goto cleanup; ++ } ++ } ++ ++ for (i = 0; i < num_sans; i++) { ++ krb5_data name = { 0, 0, NULL }; ++ ++ gen = sk_GENERAL_NAME_value(ialt, i); ++ switch (gen->type) { ++ case GEN_OTHERNAME: ++ name.length = gen->d.otherName->value->value.sequence->length; ++ name.data = (char *)gen->d.otherName->value->value.sequence->data; ++ if (princs != NULL && ++ OBJ_cmp(plgctx->id_pkinit_san, ++ gen->d.otherName->type_id) == 0) { ++#ifdef DEBUG_ASN1 ++ print_buffer_bin((unsigned char *)name.data, name.length, ++ "/tmp/pkinit_san"); ++#endif ++ ret = k5int_decode_krb5_principal_name(&name, &princs[p]); ++ if (ret) { ++ pkiDebug("%s: failed decoding pkinit san value\n", ++ __FUNCTION__); ++ } else { ++ p++; ++ num_found++; ++ } ++ } else if (upns != NULL && ++ OBJ_cmp(plgctx->id_ms_san_upn, ++ gen->d.otherName->type_id) == 0) { ++ /* Prevent abuse of embedded null characters. */ ++ if (memchr(name.data, '\0', name.length)) ++ break; ++ ret = krb5_parse_name_flags(context, name.data, ++ KRB5_PRINCIPAL_PARSE_ENTERPRISE, ++ &upns[u]); ++ if (ret) { ++ pkiDebug("%s: failed parsing ms-upn san value\n", ++ __FUNCTION__); ++ } else { ++ u++; ++ num_found++; ++ } ++ } else { ++ pkiDebug("%s: unrecognized othername oid in SAN\n", ++ __FUNCTION__); ++ continue; ++ } ++ ++ break; ++ case GEN_DNS: ++ if (dnss != NULL) { ++ /* Prevent abuse of embedded null characters. */ ++ if (memchr(gen->d.dNSName->data, '\0', gen->d.dNSName->length)) ++ break; ++ pkiDebug("%s: found dns name = %s\n", __FUNCTION__, ++ gen->d.dNSName->data); ++ dnss[d] = (unsigned char *) ++ strdup((char *)gen->d.dNSName->data); ++ if (dnss[d] == NULL) { ++ pkiDebug("%s: failed to duplicate dns name\n", ++ __FUNCTION__); ++ } else { ++ d++; ++ num_found++; ++ } ++ } ++ break; ++ default: ++ pkiDebug("%s: SAN type = %d expecting %d\n", __FUNCTION__, ++ gen->type, GEN_OTHERNAME); ++ } ++ } ++ sk_GENERAL_NAME_pop_free(ialt, GENERAL_NAME_free); + + retval = 0; + if (princs) diff --git a/Improve-PKINIT-UPN-SAN-matching.patch b/Improve-PKINIT-UPN-SAN-matching.patch new file mode 100644 index 0000000..b6170c1 --- /dev/null +++ b/Improve-PKINIT-UPN-SAN-matching.patch @@ -0,0 +1,151 @@ +From a489d1309112af9fd6f5ecf3e6e93ec87c06e319 Mon Sep 17 00:00:00 2001 +From: Matt Rogers +Date: Mon, 5 Dec 2016 12:17:59 -0500 +Subject: [PATCH] Improve PKINIT UPN SAN matching + +Add the match_client() kdcpreauth callback and use it in +verify_client_san(). match_client() preserves the direct UPN to +request principal comparison and adds a direct comparison to the +client principal, falling back to an alias DB search and comparison +against the client principal. Change crypto_retreive_X509_sans() to +parse UPN values as enterprise principals. + +[ghudson@mit.edu: use match_client for both kinds of SANs] + +ticket: 8528 (new) +(cherry picked from commit 46ff765e1fb8cbec2bb602b43311269e695dbedc) +--- + src/include/krb5/kdcpreauth_plugin.h | 13 ++++++++++ + src/kdc/kdc_preauth.c | 28 ++++++++++++++++++++-- + src/plugins/preauth/pkinit/pkinit_crypto_openssl.c | 4 +++- + src/plugins/preauth/pkinit/pkinit_srv.c | 10 ++++---- + 4 files changed, 48 insertions(+), 7 deletions(-) + +diff --git a/src/include/krb5/kdcpreauth_plugin.h b/src/include/krb5/kdcpreauth_plugin.h +index f455effae..92aa5a5a5 100644 +--- a/src/include/krb5/kdcpreauth_plugin.h ++++ b/src/include/krb5/kdcpreauth_plugin.h +@@ -221,6 +221,19 @@ typedef struct krb5_kdcpreauth_callbacks_st { + + /* End of version 3 kdcpreauth callbacks. */ + ++ /* ++ * Return true if princ matches the principal named in the request or the ++ * client principal (possibly canonicalized). If princ does not match, ++ * attempt a database lookup of princ with aliases allowed and compare the ++ * result to the client principal, returning true if it matches. ++ * Otherwise, return false. ++ */ ++ krb5_boolean (*match_client)(krb5_context context, ++ krb5_kdcpreauth_rock rock, ++ krb5_principal princ); ++ ++ /* End of version 4 kdcpreauth callbacks. */ ++ + } *krb5_kdcpreauth_callbacks; + + /* Optional: preauth plugin initialization function. */ +diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c +index 605fcb7ad..0ce79c667 100644 +--- a/src/kdc/kdc_preauth.c ++++ b/src/kdc/kdc_preauth.c +@@ -568,8 +568,31 @@ set_cookie(krb5_context context, krb5_kdcpreauth_rock rock, + return kdc_fast_set_cookie(rock->rstate, pa_type, data); + } + ++static krb5_boolean ++match_client(krb5_context context, krb5_kdcpreauth_rock rock, ++ krb5_principal princ) ++{ ++ krb5_db_entry *ent; ++ krb5_boolean match = FALSE; ++ krb5_principal req_client = rock->request->client; ++ krb5_principal client = rock->client->princ; ++ ++ /* Check for a direct match against the request principal or ++ * the post-canon client principal. */ ++ if (krb5_principal_compare_flags(context, princ, req_client, ++ KRB5_PRINCIPAL_COMPARE_ENTERPRISE) || ++ krb5_principal_compare(context, princ, client)) ++ return TRUE; ++ ++ if (krb5_db_get_principal(context, princ, KRB5_KDB_FLAG_ALIAS_OK, &ent)) ++ return FALSE; ++ match = krb5_principal_compare(context, ent->princ, client); ++ krb5_db_free_principal(context, ent); ++ return match; ++} ++ + static struct krb5_kdcpreauth_callbacks_st callbacks = { +- 3, ++ 4, + max_time_skew, + client_keys, + free_keys, +@@ -583,7 +606,8 @@ static struct krb5_kdcpreauth_callbacks_st callbacks = { + client_keyblock, + add_auth_indicator, + get_cookie, +- set_cookie ++ set_cookie, ++ match_client + }; + + static krb5_error_code +diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +index 74fffbf32..bc6e7662e 100644 +--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c ++++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +@@ -2190,7 +2190,9 @@ crypto_retrieve_X509_sans(krb5_context context, + /* Prevent abuse of embedded null characters. */ + if (memchr(name.data, '\0', name.length)) + break; +- ret = krb5_parse_name(context, name.data, &upns[u]); ++ ret = krb5_parse_name_flags(context, name.data, ++ KRB5_PRINCIPAL_PARSE_ENTERPRISE, ++ &upns[u]); + if (ret) { + pkiDebug("%s: failed parsing ms-upn san value\n", + __FUNCTION__); +diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c +index 295be25e1..b5638a367 100644 +--- a/src/plugins/preauth/pkinit/pkinit_srv.c ++++ b/src/plugins/preauth/pkinit/pkinit_srv.c +@@ -121,6 +121,8 @@ static krb5_error_code + verify_client_san(krb5_context context, + pkinit_kdc_context plgctx, + pkinit_kdc_req_context reqctx, ++ krb5_kdcpreauth_callbacks cb, ++ krb5_kdcpreauth_rock rock, + krb5_principal client, + int *valid_san) + { +@@ -171,7 +173,7 @@ verify_client_san(krb5_context context, + __FUNCTION__, client_string, san_string); + krb5_free_unparsed_name(context, san_string); + #endif +- if (krb5_principal_compare(context, princs[i], client)) { ++ if (cb->match_client(context, rock, princs[i])) { + pkiDebug("%s: pkinit san match found\n", __FUNCTION__); + *valid_san = 1; + retval = 0; +@@ -199,7 +201,7 @@ verify_client_san(krb5_context context, + __FUNCTION__, client_string, san_string); + krb5_free_unparsed_name(context, san_string); + #endif +- if (krb5_principal_compare(context, upns[i], client)) { ++ if (cb->match_client(context, rock, upns[i])) { + pkiDebug("%s: upn san match found\n", __FUNCTION__); + *valid_san = 1; + retval = 0; +@@ -387,8 +389,8 @@ pkinit_server_verify_padata(krb5_context context, + } + if (is_signed) { + +- retval = verify_client_san(context, plgctx, reqctx, request->client, +- &valid_san); ++ retval = verify_client_san(context, plgctx, reqctx, cb, rock, ++ request->client, &valid_san); + if (retval) + goto cleanup; + if (!valid_san) { diff --git a/krb5.spec b/krb5.spec index e2a3a98..79824bd 100644 --- a/krb5.spec +++ b/krb5.spec @@ -18,7 +18,7 @@ Summary: The Kerberos network authentication system Name: krb5 Version: 1.15.1 # for prerelease, should be e.g., 0.3.beta2%{?dist} -Release: 2%{?dist} +Release: 3%{?dist} # - Maybe we should explode from the now-available-to-everybody tarball instead? # http://web.mit.edu/kerberos/dist/krb5/1.13/krb5-1.13.2-signed.tar # - The sources below are stored in a lookaside cache. Upload with @@ -64,6 +64,11 @@ Patch11: krb5-1.11-kpasswdtest.patch Patch12: Build-with-Werror-implicit-int-where-supported.patch Patch15: Use-fallback-realm-for-GSSAPI-ccache-selection.patch Patch16: Use-GSSAPI-fallback-skiptest.patch +Patch17: Improve-PKINIT-UPN-SAN-matching.patch +Patch18: Add-test-cert-generation-to-make-certs.sh.patch +Patch19: Add-PKINIT-UPN-tests-to-t_pkinit.py.patch +Patch20: Deindent-crypto_retrieve_X509_sans.patch +Patch21: Add-certauth-pluggable-interface.patch License: MIT URL: http://web.mit.edu/kerberos/www/ @@ -714,6 +719,9 @@ exit 0 %{_libdir}/libkadm5srv_mit.so.* %changelog +* Wed Mar 22 2017 Robbie Harwood - 1.15.1-3 +- Backport certauth plugin and related pkinit changes + * Tue Mar 07 2017 Robbie Harwood - 1.15.1-2 - Remove duplication between subpackages - Resolves: #1250228