krb5 commit: Add GSS_KRB5_NT_X509_CERT name type

Greg Hudson <[email protected]>
Newsgroups gmane.comp.encryption.kerberos.cvs
Message-ID <[email protected]>
https://github.com/krb5/krb5/commit/f2e28f13156785851819fc74cae52100e0521690
commit f2e28f13156785851819fc74cae52100e0521690
Author: Isaac Boukris <[email protected]>
Date:   Mon Aug 12 11:13:07 2019 +0000

    Add GSS_KRB5_NT_X509_CERT name type
    
    If this name type is used for the desired_name parameter of
    gss_acquire_cred_impersonate_name(), identify the S4U2Self user by
    certificate.  Co-authored with Purand Chand <[email protected]>.
    
    [[email protected]: added documentation; updated to use a boolean at the
    GSS layer rather than a new krb5 name type; rewrote commit message]
    
    ticket: 8923 (new)

 doc/appdev/gssapi.rst                 |    6 ++++++
 src/lib/gssapi/krb5/gssapiP_krb5.h    |    1 +
 src/lib/gssapi/krb5/gssapi_krb5.c     |    3 +++
 src/lib/gssapi/krb5/gssapi_krb5.h     |    5 +++++
 src/lib/gssapi/krb5/import_name.c     |   12 +++++++++++-
 src/lib/gssapi/krb5/s4u_gss_glue.c    |    9 ++++++---
 src/lib/gssapi/libgssapi_krb5.exports |    1 +
 src/lib/gssapi32.def                  |    2 ++
 src/tests/gssapi/common.c             |    4 +++-
 src/tests/gssapi/t_imp_name.c         |    2 ++
 src/tests/gssapi/t_s4u.py             |   10 ++++++++++
 11 files changed, 50 insertions(+), 5 deletions(-)

diff --git a/doc/appdev/gssapi.rst b/doc/appdev/gssapi.rst
index 66561fd..452ead2 100644
--- a/doc/appdev/gssapi.rst
+++ b/doc/appdev/gssapi.rst
@@ -61,6 +61,12 @@ name types are supported by the krb5 mechanism:
   is defined in the ``<gssapi/gssapi_krb5.h>`` header.  (New in
   release 1.17.)
 
+* **GSS_KRB5_NT_X509_CERT**: The value should be an X.509 certificate
+  encoded according to :rfc:`5280`.  This name form can be used for
+  the desired_name parameter of gss_acquire_cred_impersonate_name(),
+  to identify the S4U2Self user by certificate.  (New in release
+  1.19.)
+
 
 Initiator credentials
 ---------------------
diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h
index 2e2c775..53d077a 100644
--- a/src/lib/gssapi/krb5/gssapiP_krb5.h
+++ b/src/lib/gssapi/krb5/gssapiP_krb5.h
@@ -163,6 +163,7 @@ typedef struct _krb5_gss_name_rec {
     krb5_principal princ;       /* immutable */
     char *service;              /* immutable */
     char *host;                 /* immutable */
+    int is_cert;                /* immutable */
     k5_mutex_t lock;            /* protects ad_context only for now */
     krb5_authdata_context ad_context;
 } krb5_gss_name_rec, *krb5_gss_name_t;
diff --git a/src/lib/gssapi/krb5/gssapi_krb5.c b/src/lib/gssapi/krb5/gssapi_krb5.c
index 128ffff..a96d7ce 100644
--- a/src/lib/gssapi/krb5/gssapi_krb5.c
+++ b/src/lib/gssapi/krb5/gssapi_krb5.c
@@ -152,6 +152,8 @@ const gss_OID_desc krb5_gss_oid_array[] = {
     {GET_CRED_IMPERSONATOR_OID_LENGTH, GET_CRED_IMPERSONATOR_OID},
     /* GSS_KRB5_NT_ENTERPRISE_NAME */
     {10, "\052\206\110\206\367\022\001\002\002\006"},
+    /* GSS_KRB5_NT_X509_CERT */
+    {10, "\052\206\110\206\367\022\001\002\002\007"},
     { 0, 0 }
 };
 
@@ -170,6 +172,7 @@ const gss_OID GSS_KRB5_NT_PRINCIPAL_NAME        = &kg_oids[5];
 const gss_OID GSS_KRB5_CRED_NO_CI_FLAGS_X       = &kg_oids[7];
 const gss_OID GSS_KRB5_GET_CRED_IMPERSONATOR    = &kg_oids[8];
 const gss_OID GSS_KRB5_NT_ENTERPRISE_NAME       = &kg_oids[9];
+const gss_OID GSS_KRB5_NT_X509_CERT             = &kg_oids[10];
 
 static const gss_OID_set_desc oidsets[] = {
     {1, &kg_oids[0]}, /* RFC OID */
diff --git a/src/lib/gssapi/krb5/gssapi_krb5.h b/src/lib/gssapi/krb5/gssapi_krb5.h
index e266b59..8141f41 100644
--- a/src/lib/gssapi/krb5/gssapi_krb5.h
+++ b/src/lib/gssapi/krb5/gssapi_krb5.h
@@ -78,6 +78,11 @@ GSS_DLLIMP extern const gss_OID GSS_KRB5_NT_ENTERPRISE_NAME;
 /* {iso(1) member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
  * krb5(2) krb5-enterprise-name(6)}. */
 
+/* Kerberos X.509 DER-encoded certificate */
+GSS_DLLIMP extern const gss_OID GSS_KRB5_NT_X509_CERT;
+/* {iso(1) member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ * krb5(2) krb5-x509-cert(7)}. */
+
 GSS_DLLIMP extern const gss_OID gss_mech_krb5;
 GSS_DLLIMP extern const gss_OID gss_mech_krb5_old;
 GSS_DLLIMP extern const gss_OID gss_mech_krb5_wrong;
diff --git a/src/lib/gssapi/krb5/import_name.c b/src/lib/gssapi/krb5/import_name.c
index 21023dd..f64635a 100644
--- a/src/lib/gssapi/krb5/import_name.c
+++ b/src/lib/gssapi/krb5/import_name.c
@@ -136,7 +136,7 @@ krb5_gss_import_name(minor_status, input_name_buffer,
 #ifndef NO_PASSWORD
     struct passwd *pw;
 #endif
-    int is_composite = 0;
+    int is_composite = 0, is_cert = 0;
     krb5_authdata_context ad_context = NULL;
     OM_uint32 status = GSS_S_FAILURE;
     krb5_gss_name_t name;
@@ -188,6 +188,14 @@ krb5_gss_import_name(minor_status, input_name_buffer,
                                    &princ);
         if (code)
             goto cleanup;
+    } else if ((input_name_type != NULL) &&
+               g_OID_equal(input_name_type, GSS_KRB5_NT_X509_CERT)) {
+        code = krb5_build_principal_ext(context, &princ, 0, NULL,
+                                        input_name_buffer->length,
+                                        input_name_buffer->value, 0);
+        if (code)
+            goto cleanup;
+        is_cert = 1;
     } else {
 #ifndef NO_PASSWORD
         uid_t uid;
@@ -315,6 +323,8 @@ krb5_gss_import_name(minor_status, input_name_buffer,
                         KG_INIT_NAME_NO_COPY, &name);
     if (code)
         goto cleanup;
+    name->is_cert = is_cert;
+
     princ = NULL;
     ad_context = NULL;
     service = host = NULL;
diff --git a/src/lib/gssapi/krb5/s4u_gss_glue.c b/src/lib/gssapi/krb5/s4u_gss_glue.c
index 126ca97..7dcfe4e 100644
--- a/src/lib/gssapi/krb5/s4u_gss_glue.c
+++ b/src/lib/gssapi/krb5/s4u_gss_glue.c
@@ -48,11 +48,15 @@ kg_impersonate_name(OM_uint32 *minor_status,
     OM_uint32 major_status;
     krb5_error_code code;
     krb5_creds in_creds, *out_creds = NULL;
+    krb5_data *subject_cert = NULL;
 
     *output_cred = NULL;
     memset(&in_creds, 0, sizeof(in_creds));
 
-    in_creds.client = user->princ;
+    if (user->is_cert)
+        subject_cert = user->princ->data;
+    else
+        in_creds.client = user->princ;
     in_creds.server = impersonator_cred->name->princ;
 
     if (impersonator_cred->req_enctypes != NULL)
@@ -77,8 +81,7 @@ kg_impersonate_name(OM_uint32 *minor_status,
     code = krb5_get_credentials_for_user(context,
                                          KRB5_GC_CANONICALIZE | KRB5_GC_NO_STORE,
                                          impersonator_cred->ccache,
-                                         &in_creds,
-                                         NULL, &out_creds);
+                                         &in_creds, subject_cert, &out_creds);
     if (code != 0) {
         krb5_free_authdata(context, in_creds.authdata);
         *minor_status = code;
diff --git a/src/lib/gssapi/libgssapi_krb5.exports b/src/lib/gssapi/libgssapi_krb5.exports
index 166acfa..fd4fced 100644
--- a/src/lib/gssapi/libgssapi_krb5.exports
+++ b/src/lib/gssapi/libgssapi_krb5.exports
@@ -12,6 +12,7 @@ GSS_C_NT_STRING_UID_NAME
 GSS_C_NT_USER_NAME
 GSS_KRB5_NT_PRINCIPAL_NAME
 GSS_KRB5_NT_ENTERPRISE_NAME
+GSS_KRB5_NT_X509_CERT
 GSS_KRB5_CRED_NO_CI_FLAGS_X
 GSS_KRB5_GET_CRED_IMPERSONATOR
 GSS_C_MA_MECH_CONCRETE
diff --git a/src/lib/gssapi32.def b/src/lib/gssapi32.def
index e6b1479..a5a1e4a 100644
--- a/src/lib/gssapi32.def
+++ b/src/lib/gssapi32.def
@@ -187,3 +187,5 @@ EXPORTS
 	GSS_C_SEC_CONTEXT_SASL_SSF			@149	DATA
 ; Added in 1.17
 	GSS_KRB5_NT_ENTERPRISE_NAME			@150 	DATA
+; Added in 1.19
+	GSS_KRB5_NT_X509_CERT				@151	DATA
diff --git a/src/tests/gssapi/common.c b/src/tests/gssapi/common.c
index 7ba72f7..b49c13d 100644
--- a/src/tests/gssapi/common.c
+++ b/src/tests/gssapi/common.c
@@ -99,10 +99,12 @@ import_name(const char *str)
         nametype = (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME;
     else if (*str == 'e')
         nametype = (gss_OID)GSS_KRB5_NT_ENTERPRISE_NAME;
+    else if (*str == 'c')
+        nametype = (gss_OID)GSS_KRB5_NT_X509_CERT;
     else if (*str == 'h')
         nametype = GSS_C_NT_HOSTBASED_SERVICE;
     if (nametype == NULL || str[1] != ':')
-        errout("names must begin with u: or p: or e: or h:");
+        errout("names must begin with u: or p: or e: or c: or h:");
     buf.value = (char *)str + 2;
     buf.length = strlen(str) - 2;
     major = gss_import_name(&minor, &buf, nametype, &name);
diff --git a/src/tests/gssapi/t_imp_name.c b/src/tests/gssapi/t_imp_name.c
index 3d73dc8..e7dbcc4 100644
--- a/src/tests/gssapi/t_imp_name.c
+++ b/src/tests/gssapi/t_imp_name.c
@@ -41,6 +41,8 @@ oid_str(char type)
         return "{ 1 2 840 113554 1 2 2 1 }";
     case 'e': /* GSS_KRB5_NT_ENTERPRISE_NAME */
         return "{ 1 2 840 113554 1 2 2 6 }";
+    case 'c': /* GSS_KRB5_NT_X509_CERT */
+        return "{ 1 2 840 113554 1 2 2 7 }";
     case 'h': /* GSS_C_NT_HOSTBASED_SERVICE */
         return "{ 1 2 840 113554 1 2 1 4 }";
     }
diff --git a/src/tests/gssapi/t_s4u.py b/src/tests/gssapi/t_s4u.py
index 8077d8c..67eba44 100755
--- a/src/tests/gssapi/t_s4u.py
+++ b/src/tests/gssapi/t_s4u.py
@@ -277,6 +277,16 @@ msgs = ('Getting initial credentials for enterprise\\@abc@SREALM',
 r1.run([kvno, '-U', 'enterprise@abc', '-F', cert_path, r1.user_princ],
        expected_trace=msgs)
 
+shutil.copyfile(savefile, r1.ccache)
+
+mark('S4U2Self using X509 certificate (GSSAPI)')
+
+r1.run(['./t_s4u', 'c:other', '-', r1.keytab])
+r1.run(['./t_s4u', 'c:user@UREALM', '-', r1.keytab])
+
+r1.run(['./t_s4u', '--spnego', 'c:other', '-', r1.keytab])
+r1.run(['./t_s4u', '--spnego', 'c:user@UREALM', '-', r1.keytab])
+
 r1.stop()
 r2.stop()
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.