Blame SOURCES/Improve-PKINIT-UPN-SAN-matching.patch

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) {