auth/kerberos: Move gse_get_session_key() to common code and use in gensec_gssapi
authorAndrew Bartlett <abartlet@samba.org>
Fri, 17 Feb 2012 02:36:35 +0000 (13:36 +1100)
committerAndrew Bartlett <abartlet@samba.org>
Fri, 17 Feb 2012 06:36:38 +0000 (17:36 +1100)
Thie ensures that both code bases use the same logic to determine the use
of NEW_SPNEGO.

Andrew Bartlett

auth/kerberos/gssapi_pac.c
libcli/auth/krb5_wrap.h
source3/include/smb_krb5.h
source3/librpc/crypto/gse.c
source4/auth/gensec/gensec_gssapi.c

index 70bc9e5..d0de11e 100644 (file)
@@ -22,6 +22,7 @@
 #ifdef HAVE_KRB5
 
 #include "libcli/auth/krb5_wrap.h"
+#include "lib/util/asn1.h"
 
 #if 0
 /* FIXME - need proper configure/waf test
@@ -47,6 +48,26 @@ const gss_OID_desc * const gss_mech_krb5_old          = krb5_gss_oid_array+1;
 const gss_OID_desc * const gss_mech_krb5_wrong        = krb5_gss_oid_array+2;
 #endif
 
+#ifndef GSS_KRB5_INQ_SSPI_SESSION_KEY_OID
+#define GSS_KRB5_INQ_SSPI_SESSION_KEY_OID_LENGTH 11
+#define GSS_KRB5_INQ_SSPI_SESSION_KEY_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x05"
+#endif
+
+gss_OID_desc gse_sesskey_inq_oid = {
+       GSS_KRB5_INQ_SSPI_SESSION_KEY_OID_LENGTH,
+       (void *)GSS_KRB5_INQ_SSPI_SESSION_KEY_OID
+};
+
+#ifndef GSS_KRB5_SESSION_KEY_ENCTYPE_OID
+#define GSS_KRB5_SESSION_KEY_ENCTYPE_OID_LENGTH 10
+#define GSS_KRB5_SESSION_KEY_ENCTYPE_OID  "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x04"
+#endif
+
+gss_OID_desc gse_sesskeytype_oid = {
+       GSS_KRB5_SESSION_KEY_ENCTYPE_OID_LENGTH,
+       (void *)GSS_KRB5_SESSION_KEY_ENCTYPE_OID
+};
+
 /* The Heimdal OID for getting the PAC */
 #define EXTRACT_PAC_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH 8
 /*                                                     EXTRACTION OID             AUTHZ ID */
@@ -149,4 +170,96 @@ NTSTATUS gssapi_obtain_pac_blob(TALLOC_CTX *mem_ctx,
 #endif
        return NT_STATUS_ACCESS_DENIED;
 }
+
+NTSTATUS gssapi_get_session_key(TALLOC_CTX *mem_ctx,
+                               gss_ctx_id_t gssapi_context,
+                               DATA_BLOB *session_key, 
+                               uint32_t *keytype)
+{
+       OM_uint32 gss_min, gss_maj;
+       gss_buffer_set_t set = GSS_C_NO_BUFFER_SET;
+
+       gss_maj = gss_inquire_sec_context_by_oid(
+                               &gss_min, gssapi_context,
+                               &gse_sesskey_inq_oid, &set);
+       if (gss_maj) {
+               DEBUG(0, ("gss_inquire_sec_context_by_oid failed [%s]\n",
+                         gssapi_error_string(mem_ctx, gss_maj, gss_min, gss_mech_krb5)));
+               return NT_STATUS_NO_USER_SESSION_KEY;
+       }
+
+       if ((set == GSS_C_NO_BUFFER_SET) ||
+           (set->count == 0)) {
+#ifdef HAVE_GSSKRB5_GET_SUBKEY
+               krb5_keyblock *subkey;
+               gss_maj = gsskrb5_get_subkey(&gss_min,
+                                            gssapi_context,
+                                            &subkey);
+               if (gss_maj != 0) {
+                       DEBUG(1, ("NO session key for this mech\n"));
+                       return NT_STATUS_NO_USER_SESSION_KEY;
+               }
+               if (session_key) {
+                       *session_key = data_blob_talloc(mem_ctx,
+                                                       KRB5_KEY_DATA(subkey), KRB5_KEY_LENGTH(subkey));
+               }
+               if (keytype) {
+                       *keytype = KRB5_KEY_TYPE(subkey);
+               }
+               krb5_free_keyblock(NULL /* should be krb5_context */, subkey);
+               return NT_STATUS_OK;
+#else
+               DEBUG(0, ("gss_inquire_sec_context_by_oid returned unknown "
+                         "OID for data in results:\n"));
+               dump_data(1, (uint8_t *)set->elements[1].value,
+                            set->elements[1].length);
+               return NT_STATUS_NO_USER_SESSION_KEY;
+#endif
+       }
+
+       if (session_key) {
+               *session_key = data_blob_talloc(mem_ctx, set->elements[0].value,
+                                               set->elements[0].length);
+       }
+
+       if (keytype) {
+               char *oid;
+               char *p, *q = NULL;
+               
+               if (set->count < 2
+                   || memcmp(set->elements[1].value,
+                             gse_sesskeytype_oid.elements,
+                             gse_sesskeytype_oid.length) != 0) {
+                       /* Perhaps a non-krb5 session key */
+                       *keytype = 0;
+                       gss_maj = gss_release_buffer_set(&gss_min, &set);
+                       return NT_STATUS_OK;
+               }
+               if (!ber_read_OID_String(mem_ctx,
+                                        data_blob_const(set->elements[1].value,
+                                                        set->elements[1].length), &oid)) {
+                       TALLOC_FREE(oid);
+                       gss_maj = gss_release_buffer_set(&gss_min, &set);
+                       return NT_STATUS_INVALID_PARAMETER;
+               }
+               p = strrchr(oid, '.');
+               if (!p) {
+                       TALLOC_FREE(oid);
+                       gss_maj = gss_release_buffer_set(&gss_min, &set);
+                       return NT_STATUS_INVALID_PARAMETER;
+               } else {
+                       p++;
+                       *keytype = strtoul(p, &q, 10);
+                       if (q == NULL || *q != '\0') {
+                               TALLOC_FREE(oid);
+                               return NT_STATUS_INVALID_PARAMETER;
+                       }
+               }
+               TALLOC_FREE(oid);
+       }
+       
+       gss_maj = gss_release_buffer_set(&gss_min, &set);
+       return NT_STATUS_OK;
+}
+
 #endif
index 814c427..01ea6ac 100644 (file)
 struct PAC_SIGNATURE_DATA;
 struct PAC_DATA;
 
+#ifdef HAVE_KRB5_KEYBLOCK_KEYVALUE /* Heimdal */
+#define KRB5_KEY_TYPE(k)       ((k)->keytype)
+#define KRB5_KEY_LENGTH(k)     ((k)->keyvalue.length)
+#define KRB5_KEY_DATA(k)       ((k)->keyvalue.data)
+#define KRB5_KEY_DATA_CAST     void
+#else /* MIT */
+#define KRB5_KEY_TYPE(k)       ((k)->enctype)
+#define KRB5_KEY_LENGTH(k)     ((k)->length)
+#define KRB5_KEY_DATA(k)       ((k)->contents)
+#define KRB5_KEY_DATA_CAST     krb5_octet
+#endif /* HAVE_KRB5_KEYBLOCK_KEYVALUE */
+
 int create_kerberos_key_from_string_direct(krb5_context context,
                                                  krb5_principal host_princ,
                                                  krb5_data *password,
@@ -76,6 +88,11 @@ NTSTATUS gssapi_obtain_pac_blob(TALLOC_CTX *mem_ctx,
                                gss_ctx_id_t gssapi_context,
                                gss_name_t gss_client_name,
                                DATA_BLOB *pac_data);
+NTSTATUS gssapi_get_session_key(TALLOC_CTX *mem_ctx,
+                               gss_ctx_id_t gssapi_context,
+                               DATA_BLOB *session_key, 
+                               uint32_t *keytype);
+
 DATA_BLOB gensec_gssapi_gen_krb5_wrap(TALLOC_CTX *mem_ctx, const DATA_BLOB *ticket, const uint8_t tok_id[2]);
 
 bool gensec_gssapi_parse_krb5_wrap(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, DATA_BLOB *ticket, uint8_t tok_id[2]);
index bc9996c..1526525 100644 (file)
@@ -66,18 +66,6 @@ typedef struct {
 #endif /* defined(HAVE_MAGIC_IN_KRB5_ADDRESS) && defined(HAVE_ADDRTYPE_IN_KRB5_ADDRESS) */
 } smb_krb5_addresses;
 
-#ifdef HAVE_KRB5_KEYBLOCK_KEYVALUE /* Heimdal */
-#define KRB5_KEY_TYPE(k)       ((k)->keytype)
-#define KRB5_KEY_LENGTH(k)     ((k)->keyvalue.length)
-#define KRB5_KEY_DATA(k)       ((k)->keyvalue.data)
-#define KRB5_KEY_DATA_CAST     void
-#else /* MIT */
-#define KRB5_KEY_TYPE(k)       ((k)->enctype)
-#define KRB5_KEY_LENGTH(k)     ((k)->length)
-#define KRB5_KEY_DATA(k)       ((k)->contents)
-#define KRB5_KEY_DATA_CAST     krb5_octet
-#endif /* HAVE_KRB5_KEYBLOCK_KEYVALUE */
-
 #ifdef HAVE_KRB5_KEYTAB_ENTRY_KEY               /* MIT */
 #define KRB5_KT_KEY(k)         (&(k)->key)
 #elif HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK          /* Heimdal */
index d8f3af0..1ce3761 100644 (file)
 #include "smb_krb5.h"
 #include "gse_krb5.h"
 
-#ifndef GSS_KRB5_INQ_SSPI_SESSION_KEY_OID
-#define GSS_KRB5_INQ_SSPI_SESSION_KEY_OID_LENGTH 11
-#define GSS_KRB5_INQ_SSPI_SESSION_KEY_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x05"
-#endif
-
-gss_OID_desc gse_sesskey_inq_oid = {
-       GSS_KRB5_INQ_SSPI_SESSION_KEY_OID_LENGTH,
-       (void *)GSS_KRB5_INQ_SSPI_SESSION_KEY_OID
-};
-
-#ifndef GSS_KRB5_SESSION_KEY_ENCTYPE_OID
-#define GSS_KRB5_SESSION_KEY_ENCTYPE_OID_LENGTH 10
-#define GSS_KRB5_SESSION_KEY_ENCTYPE_OID  "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x04"
-#endif
-
-gss_OID_desc gse_sesskeytype_oid = {
-       GSS_KRB5_SESSION_KEY_ENCTYPE_OID_LENGTH,
-       (void *)GSS_KRB5_SESSION_KEY_ENCTYPE_OID
-};
-
 static char *gse_errstr(TALLOC_CTX *mem_ctx, OM_uint32 maj, OM_uint32 min);
 
 struct gse_context {
@@ -563,96 +543,6 @@ done:
        return errstr;
 }
 
-static NTSTATUS gse_get_session_key(TALLOC_CTX *mem_ctx,
-                                   struct gse_context *gse_ctx, 
-                                   DATA_BLOB *session_key, 
-                                   uint32_t *keytype)
-{
-       OM_uint32 gss_min, gss_maj;
-       gss_buffer_set_t set = GSS_C_NO_BUFFER_SET;
-
-       gss_maj = gss_inquire_sec_context_by_oid(
-                               &gss_min, gse_ctx->gssapi_context,
-                               &gse_sesskey_inq_oid, &set);
-       if (gss_maj) {
-               DEBUG(0, ("gss_inquire_sec_context_by_oid failed [%s]\n",
-                         gse_errstr(talloc_tos(), gss_maj, gss_min)));
-               return NT_STATUS_NO_USER_SESSION_KEY;
-       }
-
-       if ((set == GSS_C_NO_BUFFER_SET) ||
-           (set->count == 0)) {
-#ifdef HAVE_GSSKRB5_GET_SUBKEY
-               krb5_keyblock *subkey;
-               gss_maj = gsskrb5_get_subkey(&gss_min,
-                                            gse_ctx->gssapi_context,
-                                            &subkey);
-               if (gss_maj != 0) {
-                       DEBUG(1, ("NO session key for this mech\n"));
-                       return NT_STATUS_NO_USER_SESSION_KEY;
-               }
-               if (session_key) {
-                       *session_key = data_blob_talloc(mem_ctx,
-                                                       KRB5_KEY_DATA(subkey), KRB5_KEY_LENGTH(subkey));
-               }
-               if (keytype) {
-                       *keytype = KRB5_KEY_TYPE(subkey);
-               }
-               krb5_free_keyblock(NULL /* should be krb5_context */, subkey);
-               return NT_STATUS_OK;
-#else
-               DEBUG(0, ("gss_inquire_sec_context_by_oid returned unknown "
-                         "OID for data in results:\n"));
-               dump_data(1, (uint8_t *)set->elements[1].value,
-                            set->elements[1].length);
-               return NT_STATUS_NO_USER_SESSION_KEY;
-#endif
-       }
-
-       if (session_key) {
-               *session_key = data_blob_talloc(mem_ctx, set->elements[0].value,
-                                               set->elements[0].length);
-       }
-
-       if (keytype) {
-               char *oid;
-               char *p, *q = NULL;
-               
-               if (set->count < 2
-                   || memcmp(set->elements[1].value,
-                             gse_sesskeytype_oid.elements,
-                             gse_sesskeytype_oid.length) != 0) {
-                       /* Perhaps a non-krb5 session key */
-                       *keytype = 0;
-                       gss_maj = gss_release_buffer_set(&gss_min, &set);
-                       return NT_STATUS_OK;
-               }
-               if (!ber_read_OID_String(talloc_tos(), 
-                                        data_blob_const(set->elements[1].value,
-                                                        set->elements[1].length), &oid)) {
-                       TALLOC_FREE(oid);
-                       gss_maj = gss_release_buffer_set(&gss_min, &set);
-                       return NT_STATUS_INVALID_PARAMETER;
-               }
-               p = strrchr(oid, '.');
-               if (!p) {
-                       TALLOC_FREE(oid);
-                       gss_maj = gss_release_buffer_set(&gss_min, &set);
-                       return NT_STATUS_INVALID_PARAMETER;
-               } else {
-                       p++;
-                       *keytype = strtoul(p, &q, 10);
-                       if (q == NULL || *q != '\0') {
-                               return NT_STATUS_INVALID_PARAMETER;
-                       }
-               }
-               TALLOC_FREE(oid);
-       }
-       
-       gss_maj = gss_release_buffer_set(&gss_min, &set);
-       return NT_STATUS_OK;
-}
-
 static size_t gse_get_signature_length(struct gse_context *gse_ctx,
                                       bool seal, size_t payload_size)
 {
@@ -1125,8 +1015,8 @@ static bool gensec_gse_have_feature(struct gensec_security *gensec_security,
                        return false;
                }
 
-               status = gse_get_session_key(talloc_tos(), 
-                                          gse_ctx, NULL, &keytype);
+               status = gssapi_get_session_key(talloc_tos(), 
+                                               gse_ctx->gssapi_context, NULL, &keytype);
                /* 
                 * We should do a proper sig on the mechListMic unless
                 * we know we have to be backwards compatible with
@@ -1168,7 +1058,7 @@ static NTSTATUS gensec_gse_session_key(struct gensec_security *gensec_security,
                talloc_get_type_abort(gensec_security->private_data,
                struct gse_context);
 
-       return gse_get_session_key(mem_ctx, gse_ctx, session_key, NULL);
+       return gssapi_get_session_key(mem_ctx, gse_ctx->gssapi_context, session_key, NULL);
 }
 
 /* Get some basic (and authorization) information about the user on
index 7f504c5..b2729a9 100644 (file)
@@ -1229,6 +1229,7 @@ static bool gensec_gssapi_have_feature(struct gensec_security *gensec_security,
        }
        if (feature & GENSEC_FEATURE_NEW_SPNEGO) {
                NTSTATUS status;
+               uint32_t keytype;
 
                if (!(gensec_gssapi_state->gss_got_flags & GSS_C_INTEG_FLAG)) {
                        return false;
@@ -1241,16 +1242,27 @@ static bool gensec_gssapi_have_feature(struct gensec_security *gensec_security,
                        return false;
                }
 
-               status = gensec_gssapi_init_lucid(gensec_gssapi_state);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return false;
-               }
-
-               if (gensec_gssapi_state->lucid->protocol == 1) {
-                       return true;
+               status = gssapi_get_session_key(gensec_gssapi_state,
+                                               gensec_gssapi_state->gssapi_context, NULL, &keytype);
+               /* 
+                * We should do a proper sig on the mechListMic unless
+                * we know we have to be backwards compatible with
+                * earlier windows versions.  
+                * 
+                * Negotiating a non-krb5
+                * mech for example should be regarded as having
+                * NEW_SPNEGO
+                */
+               if (NT_STATUS_IS_OK(status)) {
+                       switch (keytype) {
+                       case ENCTYPE_DES_CBC_CRC:
+                       case ENCTYPE_DES_CBC_MD5:
+                       case ENCTYPE_ARCFOUR_HMAC:
+                       case ENCTYPE_DES3_CBC_SHA1:
+                               return false;
+                       }
                }
-
-               return false;
+               return true;
        }
        /* We can always do async (rather than strict request/reply) packets.  */
        if (feature & GENSEC_FEATURE_ASYNC_REPLIES) {
@@ -1271,30 +1283,7 @@ static NTSTATUS gensec_gssapi_session_key(struct gensec_security *gensec_securit
 {
        struct gensec_gssapi_state *gensec_gssapi_state
                = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
-       OM_uint32 maj_stat, min_stat;
-       krb5_keyblock *subkey;
-
-       if (gensec_gssapi_state->sasl_state != STAGE_DONE) {
-               return NT_STATUS_NO_USER_SESSION_KEY;
-       }
-
-       maj_stat = gsskrb5_get_subkey(&min_stat,
-                                     gensec_gssapi_state->gssapi_context,
-                                     &subkey);
-       if (maj_stat != 0) {
-               DEBUG(1, ("NO session key for this mech\n"));
-               return NT_STATUS_NO_USER_SESSION_KEY;
-       }
-       
-       DEBUG(10, ("Got KRB5 session key of length %d%s\n",
-                  (int)KRB5_KEY_LENGTH(subkey),
-                  (gensec_gssapi_state->sasl_state == STAGE_DONE)?" (done)":""));
-       *session_key = data_blob_talloc(mem_ctx,
-                                       KRB5_KEY_DATA(subkey), KRB5_KEY_LENGTH(subkey));
-       krb5_free_keyblock(gensec_gssapi_state->smb_krb5_context->krb5_context, subkey);
-       dump_data_pw("KRB5 Session Key:\n", session_key->data, session_key->length);
-
-       return NT_STATUS_OK;
+       return gssapi_get_session_key(mem_ctx, gensec_gssapi_state->gssapi_context, session_key, NULL);
 }
 
 /* Get some basic (and authorization) information about the user on