krb5 commit: Add support to query the SSF of a GSS context

Greg Hudson <[email protected]>
Newsgroups gmane.comp.encryption.kerberos.cvs
Message-ID <[email protected]>
https://github.com/krb5/krb5/commit/7feb7da54c0321b5a3eeb6c3797846a3cf7eda28
commit 7feb7da54c0321b5a3eeb6c3797846a3cf7eda28
Author: Simo Sorce <[email protected]>
Date:   Thu Mar 30 11:27:09 2017 -0400

    Add support to query the SSF of a GSS context
    
    Cyrus SASL provides a Security Strength Factor number to assess the
    relative "strength" of the negotiated mechanism, and applications
    sometimes make access control decisions based on it.
    
    Add a call that allows us to query the mechanism that established the
    GSS security context to ask what is the current SSF, based on the
    enctype of the session key.
    
    ticket: 8569 (new)

 src/include/k5-int.h                    |    1 +
 src/lib/crypto/krb/crypto_int.h         |    1 +
 src/lib/crypto/krb/enctype_util.c       |   16 +++++++++++++++
 src/lib/crypto/krb/etypes.c             |   33 ++++++++++++++++--------------
 src/lib/crypto/libk5crypto.exports      |    1 +
 src/lib/gssapi/generic/gssapi_ext.h     |   11 ++++++++++
 src/lib/gssapi/generic/gssapi_generic.c |    9 ++++++++
 src/lib/gssapi/krb5/gssapiP_krb5.h      |    6 +++++
 src/lib/gssapi/krb5/gssapi_krb5.c       |    4 +++
 src/lib/gssapi/krb5/inq_context.c       |   27 +++++++++++++++++++++++++
 src/lib/gssapi/libgssapi_krb5.exports   |    1 +
 src/lib/gssapi32.def                    |    1 +
 src/lib/krb5_32.def                     |    3 ++
 src/tests/gssapi/t_enctypes.c           |   14 +++++++++++++
 14 files changed, 113 insertions(+), 15 deletions(-)

diff --git a/src/include/k5-int.h b/src/include/k5-int.h
index ddeebc4..78ebaf3 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -2113,6 +2113,7 @@ krb5_get_tgs_ktypes(krb5_context, krb5_const_principal, krb5_enctype **);
 krb5_boolean krb5_is_permitted_enctype(krb5_context, krb5_enctype);
 
 krb5_boolean KRB5_CALLCONV krb5int_c_weak_enctype(krb5_enctype);
+krb5_error_code k5_enctype_to_ssf(krb5_enctype enctype, unsigned int *ssf_out);
 
 krb5_error_code krb5_kdc_rep_decrypt_proc(krb5_context, const krb5_keyblock *,
                                           krb5_const_pointer, krb5_kdc_rep *);
diff --git a/src/lib/crypto/krb/crypto_int.h b/src/lib/crypto/krb/crypto_int.h
index d75b49c..e509929 100644
--- a/src/lib/crypto/krb/crypto_int.h
+++ b/src/lib/crypto/krb/crypto_int.h
@@ -111,6 +111,7 @@ struct krb5_keytypes {
     prf_func prf;
     krb5_cksumtype required_ctype;
     krb5_flags flags;
+    unsigned int ssf;
 };
 
 #define ETYPE_WEAK 1
diff --git a/src/lib/crypto/krb/enctype_util.c b/src/lib/crypto/krb/enctype_util.c
index 0ed74bd..b1b40e7 100644
--- a/src/lib/crypto/krb/enctype_util.c
+++ b/src/lib/crypto/krb/enctype_util.c
@@ -131,3 +131,19 @@ krb5_enctype_to_name(krb5_enctype enctype, krb5_boolean shortest,
         return ENOMEM;
     return 0;
 }
+
+/* The security of a mechanism cannot be summarized with a simple integer
+ * value, but we provide a per-enctype value for Cyrus SASL's SSF. */
+krb5_error_code
+k5_enctype_to_ssf(krb5_enctype enctype, unsigned int *ssf_out)
+{
+    const struct krb5_keytypes *ktp;
+
+    *ssf_out = 0;
+
+    ktp = find_enctype(enctype);
+    if (ktp == NULL)
+        return EINVAL;
+    *ssf_out = ktp->ssf;
+    return 0;
+}
diff --git a/src/lib/crypto/krb/etypes.c b/src/lib/crypto/krb/etypes.c
index 0e5e977..53d4a5c 100644
--- a/src/lib/crypto/krb/etypes.c
+++ b/src/lib/crypto/krb/etypes.c
@@ -42,7 +42,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
       krb5int_des_string_to_key, k5_rand2key_des,
       krb5int_des_prf,
       CKSUMTYPE_RSA_MD5_DES,
-      ETYPE_WEAK },
+      ETYPE_WEAK, 56 },
     { ENCTYPE_DES_CBC_MD4,
       "des-cbc-md4", { 0 }, "DES cbc mode with RSA-MD4",
       &krb5int_enc_des, &krb5int_hash_md4,
@@ -51,7 +51,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
       krb5int_des_string_to_key, k5_rand2key_des,
       krb5int_des_prf,
       CKSUMTYPE_RSA_MD4_DES,
-      ETYPE_WEAK },
+      ETYPE_WEAK, 56 },
     { ENCTYPE_DES_CBC_MD5,
       "des-cbc-md5", { "des" }, "DES cbc mode with RSA-MD5",
       &krb5int_enc_des, &krb5int_hash_md5,
@@ -60,7 +60,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
       krb5int_des_string_to_key, k5_rand2key_des,
       krb5int_des_prf,
       CKSUMTYPE_RSA_MD5_DES,
-      ETYPE_WEAK },
+      ETYPE_WEAK, 56 },
     { ENCTYPE_DES_CBC_RAW,
       "des-cbc-raw", { 0 }, "DES cbc mode raw",
       &krb5int_enc_des, NULL,
@@ -69,7 +69,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
       krb5int_des_string_to_key, k5_rand2key_des,
       krb5int_des_prf,
       0,
-      ETYPE_WEAK },
+      ETYPE_WEAK, 56 },
     { ENCTYPE_DES3_CBC_RAW,
       "des3-cbc-raw", { 0 }, "Triple DES cbc mode raw",
       &krb5int_enc_des3, NULL,
@@ -78,7 +78,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
       krb5int_dk_string_to_key, k5_rand2key_des3,
       NULL, /*PRF*/
       0,
-      ETYPE_WEAK },
+      ETYPE_WEAK, 112 },
 
     { ENCTYPE_DES3_CBC_SHA1,
       "des3-cbc-sha1", { "des3-hmac-sha1", "des3-cbc-sha1-kd" },
@@ -89,7 +89,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
       krb5int_dk_string_to_key, k5_rand2key_des3,
       krb5int_dk_prf,
       CKSUMTYPE_HMAC_SHA1_DES3,
-      0 /*flags*/ },
+      0 /*flags*/, 112 },
 
     { ENCTYPE_DES_HMAC_SHA1,
       "des-hmac-sha1", { 0 }, "DES with HMAC/sha1",
@@ -99,7 +99,10 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
       krb5int_dk_string_to_key, k5_rand2key_des,
       NULL, /*PRF*/
       0,
-      ETYPE_WEAK },
+      ETYPE_WEAK, 56 },
+
+    /* rc4-hmac uses a 128-bit key, but due to weaknesses in the RC4 cipher, we
+     * consider its strength degraded and assign it an SSF value of 64. */
     { ENCTYPE_ARCFOUR_HMAC,
       "arcfour-hmac", { "rc4-hmac", "arcfour-hmac-md5" },
       "ArcFour with HMAC/md5",
@@ -110,7 +113,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
       krb5int_arcfour_decrypt, krb5int_arcfour_string_to_key,
       k5_rand2key_direct, krb5int_arcfour_prf,
       CKSUMTYPE_HMAC_MD5_ARCFOUR,
-      0 /*flags*/ },
+      0 /*flags*/, 64 },
     { ENCTYPE_ARCFOUR_HMAC_EXP,
       "arcfour-hmac-exp", { "rc4-hmac-exp", "arcfour-hmac-md5-exp" },
       "Exportable ArcFour with HMAC/md5",
@@ -121,7 +124,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
       krb5int_arcfour_decrypt, krb5int_arcfour_string_to_key,
       k5_rand2key_direct, krb5int_arcfour_prf,
       CKSUMTYPE_HMAC_MD5_ARCFOUR,
-      ETYPE_WEAK
+      ETYPE_WEAK, 40
     },
 
     { ENCTYPE_AES128_CTS_HMAC_SHA1_96,
@@ -133,7 +136,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
       krb5int_aes_string_to_key, k5_rand2key_direct,
       krb5int_dk_prf,
       CKSUMTYPE_HMAC_SHA1_96_AES128,
-      0 /*flags*/ },
+      0 /*flags*/, 128 },
     { ENCTYPE_AES256_CTS_HMAC_SHA1_96,
       "aes256-cts-hmac-sha1-96", { "aes256-cts", "aes256-sha1" },
       "AES-256 CTS mode with 96-bit SHA-1 HMAC",
@@ -143,7 +146,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
       krb5int_aes_string_to_key, k5_rand2key_direct,
       krb5int_dk_prf,
       CKSUMTYPE_HMAC_SHA1_96_AES256,
-      0 /*flags*/ },
+      0 /*flags*/, 256 },
 
     { ENCTYPE_CAMELLIA128_CTS_CMAC,
       "camellia128-cts-cmac", { "camellia128-cts" },
@@ -155,7 +158,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
       krb5int_camellia_string_to_key, k5_rand2key_direct,
       krb5int_dk_cmac_prf,
       CKSUMTYPE_CMAC_CAMELLIA128,
-      0 /*flags*/ },
+      0 /*flags*/, 128 },
     { ENCTYPE_CAMELLIA256_CTS_CMAC,
       "camellia256-cts-cmac", { "camellia256-cts" },
       "Camellia-256 CTS mode with CMAC",
@@ -166,7 +169,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
       krb5int_camellia_string_to_key, k5_rand2key_direct,
       krb5int_dk_cmac_prf,
       CKSUMTYPE_CMAC_CAMELLIA256,
-      0 /*flags */ },
+      0 /*flags */, 256 },
 
     { ENCTYPE_AES128_CTS_HMAC_SHA256_128,
       "aes128-cts-hmac-sha256-128", { "aes128-sha2" },
@@ -177,7 +180,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
       krb5int_aes2_string_to_key, k5_rand2key_direct,
       krb5int_aes2_prf,
       CKSUMTYPE_HMAC_SHA256_128_AES128,
-      0 /*flags*/ },
+      0 /*flags*/, 128 },
     { ENCTYPE_AES256_CTS_HMAC_SHA384_192,
       "aes256-cts-hmac-sha384-192", { "aes256-sha2" },
       "AES-256 CTS mode with 192-bit SHA-384 HMAC",
@@ -187,7 +190,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
       krb5int_aes2_string_to_key, k5_rand2key_direct,
       krb5int_aes2_prf,
       CKSUMTYPE_HMAC_SHA384_192_AES256,
-      0 /*flags*/ },
+      0 /*flags*/, 256 },
 };
 
 const int krb5int_enctypes_length =
diff --git a/src/lib/crypto/libk5crypto.exports b/src/lib/crypto/libk5crypto.exports
index 447e456..82eb5f3 100644
--- a/src/lib/crypto/libk5crypto.exports
+++ b/src/lib/crypto/libk5crypto.exports
@@ -108,3 +108,4 @@ krb5int_nfold
 k5_allow_weak_pbkdf2iter
 krb5_c_prfplus
 krb5_c_derive_prfplus
+k5_enctype_to_ssf
diff --git a/src/lib/gssapi/generic/gssapi_ext.h b/src/lib/gssapi/generic/gssapi_ext.h
index 9ad4421..9d3a7e7 100644
--- a/src/lib/gssapi/generic/gssapi_ext.h
+++ b/src/lib/gssapi/generic/gssapi_ext.h
@@ -575,4 +575,15 @@ gss_import_cred(
 }
 #endif
 
+/*
+ * When used with gss_inquire_sec_context_by_oid(), return a buffer set with
+ * the first member containing an unsigned 32-bit integer in network byte
+ * order.  This is the Security Strength Factor (SSF) associated with the
+ * secure channel established by the security context.  NOTE: This value is
+ * made available solely as an indication for use by APIs like Cyrus SASL that
+ * classify the strength of a secure channel via this number.  The strength of
+ * a channel cannot necessarily be represented by a simple number.
+ */
+GSS_DLLIMP extern gss_OID GSS_C_SEC_CONTEXT_SASL_SSF;
+
 #endif /* GSSAPI_EXT_H_ */
diff --git a/src/lib/gssapi/generic/gssapi_generic.c b/src/lib/gssapi/generic/gssapi_generic.c
index 5496aa3..fa144c2 100644
--- a/src/lib/gssapi/generic/gssapi_generic.c
+++ b/src/lib/gssapi/generic/gssapi_generic.c
@@ -157,6 +157,13 @@ static const gss_OID_desc const_oids[] = {
     {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x19"},
     {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x1a"},
     {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x1b"},
+
+    /*
+     * GSS_SEC_CONTEXT_SASL_SSF_OID 1.2.840.113554.1.2.2.5.15
+     * iso(1) member-body(2) United States(840) mit(113554)
+     * infosys(1) gssapi(2) krb5(2) krb5-gssapi-ext(5) sasl-ssf(15)
+     */
+    {11, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0f"},
 };
 
 /* Here are the constants which point to the static structure above.
@@ -218,6 +225,8 @@ GSS_DLLIMP gss_const_OID GSS_C_MA_PFS               = oids+33;
 GSS_DLLIMP gss_const_OID GSS_C_MA_COMPRESS          = oids+34;
 GSS_DLLIMP gss_const_OID GSS_C_MA_CTX_TRANS         = oids+35;
 
+GSS_DLLIMP gss_OID GSS_C_SEC_CONTEXT_SASL_SSF = oids+36;
+
 static gss_OID_set_desc gss_ma_known_attrs_desc = { 27, oids+9 };
 gss_OID_set gss_ma_known_attrs = &gss_ma_known_attrs_desc;
 
diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h
index cd65966..e92be88 100644
--- a/src/lib/gssapi/krb5/gssapiP_krb5.h
+++ b/src/lib/gssapi/krb5/gssapiP_krb5.h
@@ -1144,6 +1144,12 @@ gss_krb5int_extract_authtime_from_sec_context(OM_uint32 *,
                                               const gss_OID,
                                               gss_buffer_set_t *);
 
+#define GET_SEC_CONTEXT_SASL_SSF_OID_LENGTH 11
+#define GET_SEC_CONTEXT_SASL_SSF_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0f"
+OM_uint32
+gss_krb5int_sec_context_sasl_ssf(OM_uint32 *, const gss_ctx_id_t,
+                                 const gss_OID, gss_buffer_set_t *);
+
 #define GSS_KRB5_IMPORT_CRED_OID_LENGTH 11
 #define GSS_KRB5_IMPORT_CRED_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0d"
 
diff --git a/src/lib/gssapi/krb5/gssapi_krb5.c b/src/lib/gssapi/krb5/gssapi_krb5.c
index e12b662..43930dd 100644
--- a/src/lib/gssapi/krb5/gssapi_krb5.c
+++ b/src/lib/gssapi/krb5/gssapi_krb5.c
@@ -357,6 +357,10 @@ static struct {
     {
         {GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID_LENGTH, GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID},
         gss_krb5int_extract_authtime_from_sec_context
+    },
+    {
+        {GET_SEC_CONTEXT_SASL_SSF_OID_LENGTH, GET_SEC_CONTEXT_SASL_SSF_OID},
+        gss_krb5int_sec_context_sasl_ssf
     }
 };
 
diff --git a/src/lib/gssapi/krb5/inq_context.c b/src/lib/gssapi/krb5/inq_context.c
index 9024b3c..d2e466e 100644
--- a/src/lib/gssapi/krb5/inq_context.c
+++ b/src/lib/gssapi/krb5/inq_context.c
@@ -310,3 +310,30 @@ gss_krb5int_extract_authtime_from_sec_context(OM_uint32 *minor_status,
 
     return generic_gss_add_buffer_set_member(minor_status, &rep, data_set);
 }
+
+OM_uint32
+gss_krb5int_sec_context_sasl_ssf(OM_uint32 *minor_status,
+                                 const gss_ctx_id_t context_handle,
+                                 const gss_OID desired_object,
+                                 gss_buffer_set_t *data_set)
+{
+    krb5_gss_ctx_id_rec *ctx;
+    krb5_key key;
+    krb5_error_code code;
+    gss_buffer_desc ssfbuf;
+    unsigned int ssf;
+    uint8_t buf[4];
+
+    ctx = (krb5_gss_ctx_id_rec *)context_handle;
+    key = ctx->have_acceptor_subkey ? ctx->acceptor_subkey : ctx->subkey;
+
+    code = k5_enctype_to_ssf(key->keyblock.enctype, &ssf);
+    if (code)
+        return GSS_S_FAILURE;
+
+    store_32_be(ssf, buf);
+    ssfbuf.value = buf;
+    ssfbuf.length = sizeof(buf);
+
+    return generic_gss_add_buffer_set_member(minor_status, &ssfbuf, data_set);
+}
diff --git a/src/lib/gssapi/libgssapi_krb5.exports b/src/lib/gssapi/libgssapi_krb5.exports
index 16d38e9..b07f69f 100644
--- a/src/lib/gssapi/libgssapi_krb5.exports
+++ b/src/lib/gssapi/libgssapi_krb5.exports
@@ -38,6 +38,7 @@ GSS_C_MA_CBINDINGS
 GSS_C_MA_PFS
 GSS_C_MA_COMPRESS
 GSS_C_MA_CTX_TRANS
+GSS_C_SEC_CONTEXT_SASL_SSF
 gss_accept_sec_context
 gss_acquire_cred
 gss_acquire_cred_with_password
diff --git a/src/lib/gssapi32.def b/src/lib/gssapi32.def
index 4bf8c95..842f3d5 100644
--- a/src/lib/gssapi32.def
+++ b/src/lib/gssapi32.def
@@ -184,3 +184,4 @@ EXPORTS
 	GSS_KRB5_CRED_NO_CI_FLAGS_X			@147	DATA
 ; Added in 1.16
 	GSS_KRB5_GET_CRED_IMPERSONATOR			@148	DATA
+	GSS_C_SEC_CONTEXT_SASL_SSF			@149	DATA
diff --git a/src/lib/krb5_32.def b/src/lib/krb5_32.def
index e5b560d..f7b428e 100644
--- a/src/lib/krb5_32.def
+++ b/src/lib/krb5_32.def
@@ -470,3 +470,6 @@ EXPORTS
 	krb5_get_init_creds_opt_set_pac_request		@435
 	krb5int_trace					@436 ; PRIVATE GSSAPI
 	krb5_expand_hostname				@437
+
+; new in 1.16
+	k5_enctype_to_ssf				@438 ; PRIVATE GSSAPI
diff --git a/src/tests/gssapi/t_enctypes.c b/src/tests/gssapi/t_enctypes.c
index a2ad18f..3fd31e2 100644
--- a/src/tests/gssapi/t_enctypes.c
+++ b/src/tests/gssapi/t_enctypes.c
@@ -32,6 +32,7 @@
 
 #include "k5-int.h"
 #include "common.h"
+#include "gssapi_ext.h"
 
 /*
  * This test program establishes contexts with the krb5 mech, the default
@@ -86,6 +87,9 @@ main(int argc, char *argv[])
     gss_krb5_lucid_context_v1_t *ilucid, *alucid;
     gss_krb5_rfc1964_keydata_t *i1964, *a1964;
     gss_krb5_cfx_keydata_t *icfx, *acfx;
+    gss_buffer_set_t bufset = GSS_C_NO_BUFFER_SET;
+    gss_OID ssf_oid = GSS_C_SEC_CONTEXT_SASL_SSF;
+    unsigned int ssf;
     size_t count;
     void *lptr;
     int c;
@@ -139,6 +143,16 @@ main(int argc, char *argv[])
     establish_contexts(&mech_krb5, icred, acred, tname, flags, &ictx, &actx,
                        NULL, NULL, NULL);
 
+    /* Query the SSF value and range-check the result. */
+    major = gss_inquire_sec_context_by_oid(&minor, ictx, ssf_oid, &bufset);
+    check_gsserr("gss_inquire_sec_context_by_oid(ssf)", major, minor);
+    if (bufset->elements[0].length != 4)
+        errout("SSF buffer has unexpected length");
+    ssf = load_32_be(bufset->elements[0].value);
+    if (ssf < 56 || ssf > 256)
+        errout("SSF value not within acceptable range (56-256)");
+    (void)gss_release_buffer_set(&minor, &bufset);
+
     /* Export to lucid contexts. */
     major = gss_krb5_export_lucid_sec_context(&minor, &ictx, 1, &lptr);
     check_gsserr("gss_export_lucid_sec_context(initiator)", major, minor);
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.