|
|
fab64b |
From 802cf0263965eef725208f00eccb62df0b082319 Mon Sep 17 00:00:00 2001
|
|
|
fab64b |
From: Matt Rogers <mrogers@redhat.com>
|
|
|
fab64b |
Date: Mon, 5 Dec 2016 12:17:59 -0500
|
|
|
fab64b |
Subject: [PATCH] Improve PKINIT UPN SAN matching
|
|
|
fab64b |
|
|
|
fab64b |
Add the match_client() kdcpreauth callback and use it in
|
|
|
fab64b |
verify_client_san(). match_client() preserves the direct UPN to
|
|
|
fab64b |
request principal comparison and adds a direct comparison to the
|
|
|
fab64b |
client principal, falling back to an alias DB search and comparison
|
|
|
fab64b |
against the client principal. Change crypto_retreive_X509_sans() to
|
|
|
fab64b |
parse UPN values as enterprise principals.
|
|
|
fab64b |
|
|
|
fab64b |
[ghudson@mit.edu: use match_client for both kinds of SANs]
|
|
|
fab64b |
|
|
|
fab64b |
ticket: 8528 (new)
|
|
|
fab64b |
(cherry picked from commit 46ff765e1fb8cbec2bb602b43311269e695dbedc)
|
|
|
fab64b |
---
|
|
|
665228 |
src/include/krb5/kdcpreauth_plugin.h | 13 +++++++++
|
|
|
665228 |
src/kdc/kdc_preauth.c | 28 +++++++++++++++++--
|
|
|
665228 |
.../preauth/pkinit/pkinit_crypto_openssl.c | 4 ++-
|
|
|
665228 |
src/plugins/preauth/pkinit/pkinit_srv.c | 10 ++++---
|
|
|
fab64b |
4 files changed, 48 insertions(+), 7 deletions(-)
|
|
|
fab64b |
|
|
|
fab64b |
diff --git a/src/include/krb5/kdcpreauth_plugin.h b/src/include/krb5/kdcpreauth_plugin.h
|
|
|
fab64b |
index f455effae..92aa5a5a5 100644
|
|
|
fab64b |
--- a/src/include/krb5/kdcpreauth_plugin.h
|
|
|
fab64b |
+++ b/src/include/krb5/kdcpreauth_plugin.h
|
|
|
fab64b |
@@ -221,6 +221,19 @@ typedef struct krb5_kdcpreauth_callbacks_st {
|
|
|
fab64b |
|
|
|
fab64b |
/* End of version 3 kdcpreauth callbacks. */
|
|
|
fab64b |
|
|
|
fab64b |
+ /*
|
|
|
fab64b |
+ * Return true if princ matches the principal named in the request or the
|
|
|
fab64b |
+ * client principal (possibly canonicalized). If princ does not match,
|
|
|
fab64b |
+ * attempt a database lookup of princ with aliases allowed and compare the
|
|
|
fab64b |
+ * result to the client principal, returning true if it matches.
|
|
|
fab64b |
+ * Otherwise, return false.
|
|
|
fab64b |
+ */
|
|
|
fab64b |
+ krb5_boolean (*match_client)(krb5_context context,
|
|
|
fab64b |
+ krb5_kdcpreauth_rock rock,
|
|
|
fab64b |
+ krb5_principal princ);
|
|
|
fab64b |
+
|
|
|
fab64b |
+ /* End of version 4 kdcpreauth callbacks. */
|
|
|
fab64b |
+
|
|
|
fab64b |
} *krb5_kdcpreauth_callbacks;
|
|
|
fab64b |
|
|
|
fab64b |
/* Optional: preauth plugin initialization function. */
|
|
|
fab64b |
diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c
|
|
|
fab64b |
index 605fcb7ad..0ce79c667 100644
|
|
|
fab64b |
--- a/src/kdc/kdc_preauth.c
|
|
|
fab64b |
+++ b/src/kdc/kdc_preauth.c
|
|
|
fab64b |
@@ -568,8 +568,31 @@ set_cookie(krb5_context context, krb5_kdcpreauth_rock rock,
|
|
|
fab64b |
return kdc_fast_set_cookie(rock->rstate, pa_type, data);
|
|
|
fab64b |
}
|
|
|
fab64b |
|
|
|
fab64b |
+static krb5_boolean
|
|
|
fab64b |
+match_client(krb5_context context, krb5_kdcpreauth_rock rock,
|
|
|
fab64b |
+ krb5_principal princ)
|
|
|
fab64b |
+{
|
|
|
fab64b |
+ krb5_db_entry *ent;
|
|
|
fab64b |
+ krb5_boolean match = FALSE;
|
|
|
fab64b |
+ krb5_principal req_client = rock->request->client;
|
|
|
fab64b |
+ krb5_principal client = rock->client->princ;
|
|
|
fab64b |
+
|
|
|
fab64b |
+ /* Check for a direct match against the request principal or
|
|
|
fab64b |
+ * the post-canon client principal. */
|
|
|
fab64b |
+ if (krb5_principal_compare_flags(context, princ, req_client,
|
|
|
fab64b |
+ KRB5_PRINCIPAL_COMPARE_ENTERPRISE) ||
|
|
|
fab64b |
+ krb5_principal_compare(context, princ, client))
|
|
|
fab64b |
+ return TRUE;
|
|
|
fab64b |
+
|
|
|
fab64b |
+ if (krb5_db_get_principal(context, princ, KRB5_KDB_FLAG_ALIAS_OK, &ent))
|
|
|
fab64b |
+ return FALSE;
|
|
|
fab64b |
+ match = krb5_principal_compare(context, ent->princ, client);
|
|
|
fab64b |
+ krb5_db_free_principal(context, ent);
|
|
|
fab64b |
+ return match;
|
|
|
fab64b |
+}
|
|
|
fab64b |
+
|
|
|
fab64b |
static struct krb5_kdcpreauth_callbacks_st callbacks = {
|
|
|
fab64b |
- 3,
|
|
|
fab64b |
+ 4,
|
|
|
fab64b |
max_time_skew,
|
|
|
fab64b |
client_keys,
|
|
|
fab64b |
free_keys,
|
|
|
fab64b |
@@ -583,7 +606,8 @@ static struct krb5_kdcpreauth_callbacks_st callbacks = {
|
|
|
fab64b |
client_keyblock,
|
|
|
fab64b |
add_auth_indicator,
|
|
|
fab64b |
get_cookie,
|
|
|
fab64b |
- set_cookie
|
|
|
fab64b |
+ set_cookie,
|
|
|
fab64b |
+ match_client
|
|
|
fab64b |
};
|
|
|
fab64b |
|
|
|
fab64b |
static krb5_error_code
|
|
|
fab64b |
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
|
|
|
fab64b |
index 74fffbf32..bc6e7662e 100644
|
|
|
fab64b |
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
|
|
|
fab64b |
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
|
|
|
fab64b |
@@ -2190,7 +2190,9 @@ crypto_retrieve_X509_sans(krb5_context context,
|
|
|
fab64b |
/* Prevent abuse of embedded null characters. */
|
|
|
fab64b |
if (memchr(name.data, '\0', name.length))
|
|
|
fab64b |
break;
|
|
|
fab64b |
- ret = krb5_parse_name(context, name.data, &upns[u]);
|
|
|
fab64b |
+ ret = krb5_parse_name_flags(context, name.data,
|
|
|
fab64b |
+ KRB5_PRINCIPAL_PARSE_ENTERPRISE,
|
|
|
fab64b |
+ &upns[u]);
|
|
|
fab64b |
if (ret) {
|
|
|
fab64b |
pkiDebug("%s: failed parsing ms-upn san value\n",
|
|
|
fab64b |
__FUNCTION__);
|
|
|
fab64b |
diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c
|
|
|
fab64b |
index 295be25e1..b5638a367 100644
|
|
|
fab64b |
--- a/src/plugins/preauth/pkinit/pkinit_srv.c
|
|
|
fab64b |
+++ b/src/plugins/preauth/pkinit/pkinit_srv.c
|
|
|
fab64b |
@@ -121,6 +121,8 @@ static krb5_error_code
|
|
|
fab64b |
verify_client_san(krb5_context context,
|
|
|
fab64b |
pkinit_kdc_context plgctx,
|
|
|
fab64b |
pkinit_kdc_req_context reqctx,
|
|
|
fab64b |
+ krb5_kdcpreauth_callbacks cb,
|
|
|
fab64b |
+ krb5_kdcpreauth_rock rock,
|
|
|
fab64b |
krb5_principal client,
|
|
|
fab64b |
int *valid_san)
|
|
|
fab64b |
{
|
|
|
fab64b |
@@ -171,7 +173,7 @@ verify_client_san(krb5_context context,
|
|
|
fab64b |
__FUNCTION__, client_string, san_string);
|
|
|
fab64b |
krb5_free_unparsed_name(context, san_string);
|
|
|
fab64b |
#endif
|
|
|
fab64b |
- if (krb5_principal_compare(context, princs[i], client)) {
|
|
|
fab64b |
+ if (cb->match_client(context, rock, princs[i])) {
|
|
|
fab64b |
pkiDebug("%s: pkinit san match found\n", __FUNCTION__);
|
|
|
fab64b |
*valid_san = 1;
|
|
|
fab64b |
retval = 0;
|
|
|
fab64b |
@@ -199,7 +201,7 @@ verify_client_san(krb5_context context,
|
|
|
fab64b |
__FUNCTION__, client_string, san_string);
|
|
|
fab64b |
krb5_free_unparsed_name(context, san_string);
|
|
|
fab64b |
#endif
|
|
|
fab64b |
- if (krb5_principal_compare(context, upns[i], client)) {
|
|
|
fab64b |
+ if (cb->match_client(context, rock, upns[i])) {
|
|
|
fab64b |
pkiDebug("%s: upn san match found\n", __FUNCTION__);
|
|
|
fab64b |
*valid_san = 1;
|
|
|
fab64b |
retval = 0;
|
|
|
fab64b |
@@ -387,8 +389,8 @@ pkinit_server_verify_padata(krb5_context context,
|
|
|
fab64b |
}
|
|
|
fab64b |
if (is_signed) {
|
|
|
fab64b |
|
|
|
fab64b |
- retval = verify_client_san(context, plgctx, reqctx, request->client,
|
|
|
fab64b |
- &valid_san);
|
|
|
fab64b |
+ retval = verify_client_san(context, plgctx, reqctx, cb, rock,
|
|
|
fab64b |
+ request->client, &valid_san);
|
|
|
fab64b |
if (retval)
|
|
|
fab64b |
goto cleanup;
|
|
|
fab64b |
if (!valid_san) {
|