Blame SOURCES/Add-support-to-query-the-SSF-of-a-GSS-context.patch

e58a44
From 1f7d42707585e552842455857070fff8957fcb7c Mon Sep 17 00:00:00 2001
e58a44
From: Simo Sorce <simo@redhat.com>
e58a44
Date: Thu, 30 Mar 2017 11:27:09 -0400
e58a44
Subject: [PATCH] Add support to query the SSF of a GSS context
e58a44
e58a44
Cyrus SASL provides a Security Strength Factor number to assess the
e58a44
relative "strength" of the negotiated mechanism, and applications
e58a44
sometimes make access control decisions based on it.
e58a44
e58a44
Add a call that allows us to query the mechanism that established the
e58a44
GSS security context to ask what is the current SSF, based on the
e58a44
enctype of the session key.
e58a44
e58a44
ticket: 8569 (new)
e58a44
(cherry picked from commit 7feb7da54c0321b5a3eeb6c3797846a3cf7eda28)
e58a44
[rharwood@redhat.com: stub out GSS_KRB5_GET_CRED_IMPERSONATOR]
e58a44
---
e58a44
 src/include/k5-int.h                    |  1 +
e58a44
 src/lib/crypto/krb/crypto_int.h         |  1 +
665228
 src/lib/crypto/krb/enctype_util.c       | 16 ++++++++++++
665228
 src/lib/crypto/krb/etypes.c             | 33 ++++++++++++++-----------
e58a44
 src/lib/crypto/libk5crypto.exports      |  1 +
665228
 src/lib/gssapi/generic/gssapi_ext.h     | 11 +++++++++
665228
 src/lib/gssapi/generic/gssapi_generic.c |  9 +++++++
665228
 src/lib/gssapi/krb5/gssapiP_krb5.h      |  6 +++++
665228
 src/lib/gssapi/krb5/gssapi_krb5.c       |  4 +++
665228
 src/lib/gssapi/krb5/inq_context.c       | 27 ++++++++++++++++++++
e58a44
 src/lib/gssapi/libgssapi_krb5.exports   |  1 +
e58a44
 src/lib/gssapi32.def                    |  3 +++
e58a44
 src/lib/krb5_32.def                     |  3 +++
665228
 src/tests/gssapi/t_enctypes.c           | 14 +++++++++++
e58a44
 14 files changed, 115 insertions(+), 15 deletions(-)
e58a44
e58a44
diff --git a/src/include/k5-int.h b/src/include/k5-int.h
e58a44
index cea644d0a..06ca2b66d 100644
e58a44
--- a/src/include/k5-int.h
e58a44
+++ b/src/include/k5-int.h
e58a44
@@ -2114,6 +2114,7 @@ krb5_get_tgs_ktypes(krb5_context, krb5_const_principal, krb5_enctype **);
e58a44
 krb5_boolean krb5_is_permitted_enctype(krb5_context, krb5_enctype);
e58a44
 
e58a44
 krb5_boolean KRB5_CALLCONV krb5int_c_weak_enctype(krb5_enctype);
e58a44
+krb5_error_code k5_enctype_to_ssf(krb5_enctype enctype, unsigned int *ssf_out);
e58a44
 
e58a44
 krb5_error_code krb5_kdc_rep_decrypt_proc(krb5_context, const krb5_keyblock *,
e58a44
                                           krb5_const_pointer, krb5_kdc_rep *);
e58a44
diff --git a/src/lib/crypto/krb/crypto_int.h b/src/lib/crypto/krb/crypto_int.h
e58a44
index d75b49c69..e5099291e 100644
e58a44
--- a/src/lib/crypto/krb/crypto_int.h
e58a44
+++ b/src/lib/crypto/krb/crypto_int.h
e58a44
@@ -111,6 +111,7 @@ struct krb5_keytypes {
e58a44
     prf_func prf;
e58a44
     krb5_cksumtype required_ctype;
e58a44
     krb5_flags flags;
e58a44
+    unsigned int ssf;
e58a44
 };
e58a44
 
e58a44
 #define ETYPE_WEAK 1
e58a44
diff --git a/src/lib/crypto/krb/enctype_util.c b/src/lib/crypto/krb/enctype_util.c
e58a44
index 0ed74bd6e..b1b40e7ec 100644
e58a44
--- a/src/lib/crypto/krb/enctype_util.c
e58a44
+++ b/src/lib/crypto/krb/enctype_util.c
e58a44
@@ -131,3 +131,19 @@ krb5_enctype_to_name(krb5_enctype enctype, krb5_boolean shortest,
e58a44
         return ENOMEM;
e58a44
     return 0;
e58a44
 }
e58a44
+
e58a44
+/* The security of a mechanism cannot be summarized with a simple integer
e58a44
+ * value, but we provide a per-enctype value for Cyrus SASL's SSF. */
e58a44
+krb5_error_code
e58a44
+k5_enctype_to_ssf(krb5_enctype enctype, unsigned int *ssf_out)
e58a44
+{
e58a44
+    const struct krb5_keytypes *ktp;
e58a44
+
e58a44
+    *ssf_out = 0;
e58a44
+
e58a44
+    ktp = find_enctype(enctype);
e58a44
+    if (ktp == NULL)
e58a44
+        return EINVAL;
e58a44
+    *ssf_out = ktp->ssf;
e58a44
+    return 0;
e58a44
+}
e58a44
diff --git a/src/lib/crypto/krb/etypes.c b/src/lib/crypto/krb/etypes.c
e58a44
index 0e5e977d4..53d4a5c79 100644
e58a44
--- a/src/lib/crypto/krb/etypes.c
e58a44
+++ b/src/lib/crypto/krb/etypes.c
e58a44
@@ -42,7 +42,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
e58a44
       krb5int_des_string_to_key, k5_rand2key_des,
e58a44
       krb5int_des_prf,
e58a44
       CKSUMTYPE_RSA_MD5_DES,
e58a44
-      ETYPE_WEAK },
e58a44
+      ETYPE_WEAK, 56 },
e58a44
     { ENCTYPE_DES_CBC_MD4,
e58a44
       "des-cbc-md4", { 0 }, "DES cbc mode with RSA-MD4",
e58a44
       &krb5int_enc_des, &krb5int_hash_md4,
e58a44
@@ -51,7 +51,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
e58a44
       krb5int_des_string_to_key, k5_rand2key_des,
e58a44
       krb5int_des_prf,
e58a44
       CKSUMTYPE_RSA_MD4_DES,
e58a44
-      ETYPE_WEAK },
e58a44
+      ETYPE_WEAK, 56 },
e58a44
     { ENCTYPE_DES_CBC_MD5,
e58a44
       "des-cbc-md5", { "des" }, "DES cbc mode with RSA-MD5",
e58a44
       &krb5int_enc_des, &krb5int_hash_md5,
e58a44
@@ -60,7 +60,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
e58a44
       krb5int_des_string_to_key, k5_rand2key_des,
e58a44
       krb5int_des_prf,
e58a44
       CKSUMTYPE_RSA_MD5_DES,
e58a44
-      ETYPE_WEAK },
e58a44
+      ETYPE_WEAK, 56 },
e58a44
     { ENCTYPE_DES_CBC_RAW,
e58a44
       "des-cbc-raw", { 0 }, "DES cbc mode raw",
e58a44
       &krb5int_enc_des, NULL,
e58a44
@@ -69,7 +69,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
e58a44
       krb5int_des_string_to_key, k5_rand2key_des,
e58a44
       krb5int_des_prf,
e58a44
       0,
e58a44
-      ETYPE_WEAK },
e58a44
+      ETYPE_WEAK, 56 },
e58a44
     { ENCTYPE_DES3_CBC_RAW,
e58a44
       "des3-cbc-raw", { 0 }, "Triple DES cbc mode raw",
e58a44
       &krb5int_enc_des3, NULL,
e58a44
@@ -78,7 +78,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
e58a44
       krb5int_dk_string_to_key, k5_rand2key_des3,
e58a44
       NULL, /*PRF*/
e58a44
       0,
e58a44
-      ETYPE_WEAK },
e58a44
+      ETYPE_WEAK, 112 },
e58a44
 
e58a44
     { ENCTYPE_DES3_CBC_SHA1,
e58a44
       "des3-cbc-sha1", { "des3-hmac-sha1", "des3-cbc-sha1-kd" },
e58a44
@@ -89,7 +89,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
e58a44
       krb5int_dk_string_to_key, k5_rand2key_des3,
e58a44
       krb5int_dk_prf,
e58a44
       CKSUMTYPE_HMAC_SHA1_DES3,
e58a44
-      0 /*flags*/ },
e58a44
+      0 /*flags*/, 112 },
e58a44
 
e58a44
     { ENCTYPE_DES_HMAC_SHA1,
e58a44
       "des-hmac-sha1", { 0 }, "DES with HMAC/sha1",
e58a44
@@ -99,7 +99,10 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
e58a44
       krb5int_dk_string_to_key, k5_rand2key_des,
e58a44
       NULL, /*PRF*/
e58a44
       0,
e58a44
-      ETYPE_WEAK },
e58a44
+      ETYPE_WEAK, 56 },
e58a44
+
e58a44
+    /* rc4-hmac uses a 128-bit key, but due to weaknesses in the RC4 cipher, we
e58a44
+     * consider its strength degraded and assign it an SSF value of 64. */
e58a44
     { ENCTYPE_ARCFOUR_HMAC,
e58a44
       "arcfour-hmac", { "rc4-hmac", "arcfour-hmac-md5" },
e58a44
       "ArcFour with HMAC/md5",
e58a44
@@ -110,7 +113,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
e58a44
       krb5int_arcfour_decrypt, krb5int_arcfour_string_to_key,
e58a44
       k5_rand2key_direct, krb5int_arcfour_prf,
e58a44
       CKSUMTYPE_HMAC_MD5_ARCFOUR,
e58a44
-      0 /*flags*/ },
e58a44
+      0 /*flags*/, 64 },
e58a44
     { ENCTYPE_ARCFOUR_HMAC_EXP,
e58a44
       "arcfour-hmac-exp", { "rc4-hmac-exp", "arcfour-hmac-md5-exp" },
e58a44
       "Exportable ArcFour with HMAC/md5",
e58a44
@@ -121,7 +124,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
e58a44
       krb5int_arcfour_decrypt, krb5int_arcfour_string_to_key,
e58a44
       k5_rand2key_direct, krb5int_arcfour_prf,
e58a44
       CKSUMTYPE_HMAC_MD5_ARCFOUR,
e58a44
-      ETYPE_WEAK
e58a44
+      ETYPE_WEAK, 40
e58a44
     },
e58a44
 
e58a44
     { ENCTYPE_AES128_CTS_HMAC_SHA1_96,
e58a44
@@ -133,7 +136,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
e58a44
       krb5int_aes_string_to_key, k5_rand2key_direct,
e58a44
       krb5int_dk_prf,
e58a44
       CKSUMTYPE_HMAC_SHA1_96_AES128,
e58a44
-      0 /*flags*/ },
e58a44
+      0 /*flags*/, 128 },
e58a44
     { ENCTYPE_AES256_CTS_HMAC_SHA1_96,
e58a44
       "aes256-cts-hmac-sha1-96", { "aes256-cts", "aes256-sha1" },
e58a44
       "AES-256 CTS mode with 96-bit SHA-1 HMAC",
e58a44
@@ -143,7 +146,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
e58a44
       krb5int_aes_string_to_key, k5_rand2key_direct,
e58a44
       krb5int_dk_prf,
e58a44
       CKSUMTYPE_HMAC_SHA1_96_AES256,
e58a44
-      0 /*flags*/ },
e58a44
+      0 /*flags*/, 256 },
e58a44
 
e58a44
     { ENCTYPE_CAMELLIA128_CTS_CMAC,
e58a44
       "camellia128-cts-cmac", { "camellia128-cts" },
e58a44
@@ -155,7 +158,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
e58a44
       krb5int_camellia_string_to_key, k5_rand2key_direct,
e58a44
       krb5int_dk_cmac_prf,
e58a44
       CKSUMTYPE_CMAC_CAMELLIA128,
e58a44
-      0 /*flags*/ },
e58a44
+      0 /*flags*/, 128 },
e58a44
     { ENCTYPE_CAMELLIA256_CTS_CMAC,
e58a44
       "camellia256-cts-cmac", { "camellia256-cts" },
e58a44
       "Camellia-256 CTS mode with CMAC",
e58a44
@@ -166,7 +169,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
e58a44
       krb5int_camellia_string_to_key, k5_rand2key_direct,
e58a44
       krb5int_dk_cmac_prf,
e58a44
       CKSUMTYPE_CMAC_CAMELLIA256,
e58a44
-      0 /*flags */ },
e58a44
+      0 /*flags */, 256 },
e58a44
 
e58a44
     { ENCTYPE_AES128_CTS_HMAC_SHA256_128,
e58a44
       "aes128-cts-hmac-sha256-128", { "aes128-sha2" },
e58a44
@@ -177,7 +180,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
e58a44
       krb5int_aes2_string_to_key, k5_rand2key_direct,
e58a44
       krb5int_aes2_prf,
e58a44
       CKSUMTYPE_HMAC_SHA256_128_AES128,
e58a44
-      0 /*flags*/ },
e58a44
+      0 /*flags*/, 128 },
e58a44
     { ENCTYPE_AES256_CTS_HMAC_SHA384_192,
e58a44
       "aes256-cts-hmac-sha384-192", { "aes256-sha2" },
e58a44
       "AES-256 CTS mode with 192-bit SHA-384 HMAC",
e58a44
@@ -187,7 +190,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
e58a44
       krb5int_aes2_string_to_key, k5_rand2key_direct,
e58a44
       krb5int_aes2_prf,
e58a44
       CKSUMTYPE_HMAC_SHA384_192_AES256,
e58a44
-      0 /*flags*/ },
e58a44
+      0 /*flags*/, 256 },
e58a44
 };
e58a44
 
e58a44
 const int krb5int_enctypes_length =
e58a44
diff --git a/src/lib/crypto/libk5crypto.exports b/src/lib/crypto/libk5crypto.exports
e58a44
index 447e45644..82eb5f30c 100644
e58a44
--- a/src/lib/crypto/libk5crypto.exports
e58a44
+++ b/src/lib/crypto/libk5crypto.exports
e58a44
@@ -108,3 +108,4 @@ krb5int_nfold
e58a44
 k5_allow_weak_pbkdf2iter
e58a44
 krb5_c_prfplus
e58a44
 krb5_c_derive_prfplus
e58a44
+k5_enctype_to_ssf
e58a44
diff --git a/src/lib/gssapi/generic/gssapi_ext.h b/src/lib/gssapi/generic/gssapi_ext.h
e58a44
index 9ad44216d..9d3a7e736 100644
e58a44
--- a/src/lib/gssapi/generic/gssapi_ext.h
e58a44
+++ b/src/lib/gssapi/generic/gssapi_ext.h
e58a44
@@ -575,4 +575,15 @@ gss_import_cred(
e58a44
 }
e58a44
 #endif
e58a44
 
e58a44
+/*
e58a44
+ * When used with gss_inquire_sec_context_by_oid(), return a buffer set with
e58a44
+ * the first member containing an unsigned 32-bit integer in network byte
e58a44
+ * order.  This is the Security Strength Factor (SSF) associated with the
e58a44
+ * secure channel established by the security context.  NOTE: This value is
e58a44
+ * made available solely as an indication for use by APIs like Cyrus SASL that
e58a44
+ * classify the strength of a secure channel via this number.  The strength of
e58a44
+ * a channel cannot necessarily be represented by a simple number.
e58a44
+ */
e58a44
+GSS_DLLIMP extern gss_OID GSS_C_SEC_CONTEXT_SASL_SSF;
e58a44
+
e58a44
 #endif /* GSSAPI_EXT_H_ */
e58a44
diff --git a/src/lib/gssapi/generic/gssapi_generic.c b/src/lib/gssapi/generic/gssapi_generic.c
e58a44
index 5496aa335..fa144c2bf 100644
e58a44
--- a/src/lib/gssapi/generic/gssapi_generic.c
e58a44
+++ b/src/lib/gssapi/generic/gssapi_generic.c
e58a44
@@ -157,6 +157,13 @@ static const gss_OID_desc const_oids[] = {
e58a44
     {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x19"},
e58a44
     {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x1a"},
e58a44
     {7, (void *)"\x2b\x06\x01\x05\x05\x0d\x1b"},
e58a44
+
e58a44
+    /*
e58a44
+     * GSS_SEC_CONTEXT_SASL_SSF_OID 1.2.840.113554.1.2.2.5.15
e58a44
+     * iso(1) member-body(2) United States(840) mit(113554)
e58a44
+     * infosys(1) gssapi(2) krb5(2) krb5-gssapi-ext(5) sasl-ssf(15)
e58a44
+     */
e58a44
+    {11, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0f"},
e58a44
 };
e58a44
 
e58a44
 /* Here are the constants which point to the static structure above.
e58a44
@@ -218,6 +225,8 @@ GSS_DLLIMP gss_const_OID GSS_C_MA_PFS               = oids+33;
e58a44
 GSS_DLLIMP gss_const_OID GSS_C_MA_COMPRESS          = oids+34;
e58a44
 GSS_DLLIMP gss_const_OID GSS_C_MA_CTX_TRANS         = oids+35;
e58a44
 
e58a44
+GSS_DLLIMP gss_OID GSS_C_SEC_CONTEXT_SASL_SSF = oids+36;
e58a44
+
e58a44
 static gss_OID_set_desc gss_ma_known_attrs_desc = { 27, oids+9 };
e58a44
 gss_OID_set gss_ma_known_attrs = &gss_ma_known_attrs_desc;
e58a44
 
e58a44
diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h
e58a44
index d7bdef7e2..ef030707e 100644
e58a44
--- a/src/lib/gssapi/krb5/gssapiP_krb5.h
e58a44
+++ b/src/lib/gssapi/krb5/gssapiP_krb5.h
e58a44
@@ -1144,6 +1144,12 @@ gss_krb5int_extract_authtime_from_sec_context(OM_uint32 *,
e58a44
                                               const gss_OID,
e58a44
                                               gss_buffer_set_t *);
e58a44
 
e58a44
+#define GET_SEC_CONTEXT_SASL_SSF_OID_LENGTH 11
e58a44
+#define GET_SEC_CONTEXT_SASL_SSF_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0f"
e58a44
+OM_uint32
e58a44
+gss_krb5int_sec_context_sasl_ssf(OM_uint32 *, const gss_ctx_id_t,
e58a44
+                                 const gss_OID, gss_buffer_set_t *);
e58a44
+
e58a44
 #define GSS_KRB5_IMPORT_CRED_OID_LENGTH 11
e58a44
 #define GSS_KRB5_IMPORT_CRED_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0d"
e58a44
 
e58a44
diff --git a/src/lib/gssapi/krb5/gssapi_krb5.c b/src/lib/gssapi/krb5/gssapi_krb5.c
e58a44
index 99092ccab..de4131980 100644
e58a44
--- a/src/lib/gssapi/krb5/gssapi_krb5.c
e58a44
+++ b/src/lib/gssapi/krb5/gssapi_krb5.c
e58a44
@@ -352,6 +352,10 @@ static struct {
e58a44
     {
e58a44
         {GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID_LENGTH, GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID},
e58a44
         gss_krb5int_extract_authtime_from_sec_context
e58a44
+    },
e58a44
+    {
e58a44
+        {GET_SEC_CONTEXT_SASL_SSF_OID_LENGTH, GET_SEC_CONTEXT_SASL_SSF_OID},
e58a44
+        gss_krb5int_sec_context_sasl_ssf
e58a44
     }
e58a44
 };
e58a44
 
e58a44
diff --git a/src/lib/gssapi/krb5/inq_context.c b/src/lib/gssapi/krb5/inq_context.c
e58a44
index 9024b3c7e..d2e466e60 100644
e58a44
--- a/src/lib/gssapi/krb5/inq_context.c
e58a44
+++ b/src/lib/gssapi/krb5/inq_context.c
e58a44
@@ -310,3 +310,30 @@ gss_krb5int_extract_authtime_from_sec_context(OM_uint32 *minor_status,
e58a44
 
e58a44
     return generic_gss_add_buffer_set_member(minor_status, &rep, data_set);
e58a44
 }
e58a44
+
e58a44
+OM_uint32
e58a44
+gss_krb5int_sec_context_sasl_ssf(OM_uint32 *minor_status,
e58a44
+                                 const gss_ctx_id_t context_handle,
e58a44
+                                 const gss_OID desired_object,
e58a44
+                                 gss_buffer_set_t *data_set)
e58a44
+{
e58a44
+    krb5_gss_ctx_id_rec *ctx;
e58a44
+    krb5_key key;
e58a44
+    krb5_error_code code;
e58a44
+    gss_buffer_desc ssfbuf;
e58a44
+    unsigned int ssf;
e58a44
+    uint8_t buf[4];
e58a44
+
e58a44
+    ctx = (krb5_gss_ctx_id_rec *)context_handle;
e58a44
+    key = ctx->have_acceptor_subkey ? ctx->acceptor_subkey : ctx->subkey;
e58a44
+
e58a44
+    code = k5_enctype_to_ssf(key->keyblock.enctype, &ssf;;
e58a44
+    if (code)
e58a44
+        return GSS_S_FAILURE;
e58a44
+
e58a44
+    store_32_be(ssf, buf);
e58a44
+    ssfbuf.value = buf;
e58a44
+    ssfbuf.length = sizeof(buf);
e58a44
+
e58a44
+    return generic_gss_add_buffer_set_member(minor_status, &ssfbuf, data_set);
e58a44
+}
e58a44
diff --git a/src/lib/gssapi/libgssapi_krb5.exports b/src/lib/gssapi/libgssapi_krb5.exports
e58a44
index 9facb3f42..936540e41 100644
e58a44
--- a/src/lib/gssapi/libgssapi_krb5.exports
e58a44
+++ b/src/lib/gssapi/libgssapi_krb5.exports
e58a44
@@ -37,6 +37,7 @@ GSS_C_MA_CBINDINGS
e58a44
 GSS_C_MA_PFS
e58a44
 GSS_C_MA_COMPRESS
e58a44
 GSS_C_MA_CTX_TRANS
e58a44
+GSS_C_SEC_CONTEXT_SASL_SSF
e58a44
 gss_accept_sec_context
e58a44
 gss_acquire_cred
e58a44
 gss_acquire_cred_with_password
e58a44
diff --git a/src/lib/gssapi32.def b/src/lib/gssapi32.def
e58a44
index 362b9bce8..dff057754 100644
e58a44
--- a/src/lib/gssapi32.def
e58a44
+++ b/src/lib/gssapi32.def
e58a44
@@ -182,3 +182,6 @@ EXPORTS
e58a44
 	gss_verify_mic_iov				@146
e58a44
 ; Added in 1.14
e58a44
 	GSS_KRB5_CRED_NO_CI_FLAGS_X			@147	DATA
e58a44
+; Added in 1.16
e58a44
+;	GSS_KRB5_GET_CRED_IMPERSONATOR			@148	DATA
e58a44
+	GSS_C_SEC_CONTEXT_SASL_SSF			@149	DATA
e58a44
diff --git a/src/lib/krb5_32.def b/src/lib/krb5_32.def
e58a44
index e5b560dfc..f7b428e16 100644
e58a44
--- a/src/lib/krb5_32.def
e58a44
+++ b/src/lib/krb5_32.def
e58a44
@@ -470,3 +470,6 @@ EXPORTS
e58a44
 	krb5_get_init_creds_opt_set_pac_request		@435
e58a44
 	krb5int_trace					@436 ; PRIVATE GSSAPI
e58a44
 	krb5_expand_hostname				@437
e58a44
+
e58a44
+; new in 1.16
e58a44
+	k5_enctype_to_ssf				@438 ; PRIVATE GSSAPI
e58a44
diff --git a/src/tests/gssapi/t_enctypes.c b/src/tests/gssapi/t_enctypes.c
e58a44
index a2ad18f47..3fd31e2f8 100644
e58a44
--- a/src/tests/gssapi/t_enctypes.c
e58a44
+++ b/src/tests/gssapi/t_enctypes.c
e58a44
@@ -32,6 +32,7 @@
e58a44
 
e58a44
 #include "k5-int.h"
e58a44
 #include "common.h"
e58a44
+#include "gssapi_ext.h"
e58a44
 
e58a44
 /*
e58a44
  * This test program establishes contexts with the krb5 mech, the default
e58a44
@@ -86,6 +87,9 @@ main(int argc, char *argv[])
e58a44
     gss_krb5_lucid_context_v1_t *ilucid, *alucid;
e58a44
     gss_krb5_rfc1964_keydata_t *i1964, *a1964;
e58a44
     gss_krb5_cfx_keydata_t *icfx, *acfx;
e58a44
+    gss_buffer_set_t bufset = GSS_C_NO_BUFFER_SET;
e58a44
+    gss_OID ssf_oid = GSS_C_SEC_CONTEXT_SASL_SSF;
e58a44
+    unsigned int ssf;
e58a44
     size_t count;
e58a44
     void *lptr;
e58a44
     int c;
e58a44
@@ -139,6 +143,16 @@ main(int argc, char *argv[])
e58a44
     establish_contexts(&mech_krb5, icred, acred, tname, flags, &ictx, &actx,
e58a44
                        NULL, NULL, NULL);
e58a44
 
e58a44
+    /* Query the SSF value and range-check the result. */
e58a44
+    major = gss_inquire_sec_context_by_oid(&minor, ictx, ssf_oid, &bufset);
e58a44
+    check_gsserr("gss_inquire_sec_context_by_oid(ssf)", major, minor);
e58a44
+    if (bufset->elements[0].length != 4)
e58a44
+        errout("SSF buffer has unexpected length");
e58a44
+    ssf = load_32_be(bufset->elements[0].value);
e58a44
+    if (ssf < 56 || ssf > 256)
e58a44
+        errout("SSF value not within acceptable range (56-256)");
e58a44
+    (void)gss_release_buffer_set(&minor, &bufset);
e58a44
+
e58a44
     /* Export to lucid contexts. */
e58a44
     major = gss_krb5_export_lucid_sec_context(&minor, &ictx, 1, &lptr);
e58a44
     check_gsserr("gss_export_lucid_sec_context(initiator)", major, minor);