1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-22 13:34:15 +03:00

auth/kerberos: Move gse_get_session_key() to common code and use in gensec_gssapi

Thie ensures that both code bases use the same logic to determine the use
of NEW_SPNEGO.

Andrew Bartlett
This commit is contained in:
Andrew Bartlett 2012-02-17 13:36:35 +11:00
parent a315350341
commit 674278d5b0
5 changed files with 155 additions and 158 deletions

View File

@ -22,6 +22,7 @@
#ifdef HAVE_KRB5 #ifdef HAVE_KRB5
#include "libcli/auth/krb5_wrap.h" #include "libcli/auth/krb5_wrap.h"
#include "lib/util/asn1.h"
#if 0 #if 0
/* FIXME - need proper configure/waf test /* 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; const gss_OID_desc * const gss_mech_krb5_wrong = krb5_gss_oid_array+2;
#endif #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 */ /* The Heimdal OID for getting the PAC */
#define EXTRACT_PAC_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH 8 #define EXTRACT_PAC_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH 8
/* EXTRACTION OID AUTHZ ID */ /* EXTRACTION OID AUTHZ ID */
@ -149,4 +170,96 @@ NTSTATUS gssapi_obtain_pac_blob(TALLOC_CTX *mem_ctx,
#endif #endif
return NT_STATUS_ACCESS_DENIED; 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 #endif

View File

@ -24,6 +24,18 @@
struct PAC_SIGNATURE_DATA; struct PAC_SIGNATURE_DATA;
struct PAC_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, int create_kerberos_key_from_string_direct(krb5_context context,
krb5_principal host_princ, krb5_principal host_princ,
krb5_data *password, krb5_data *password,
@ -76,6 +88,11 @@ NTSTATUS gssapi_obtain_pac_blob(TALLOC_CTX *mem_ctx,
gss_ctx_id_t gssapi_context, gss_ctx_id_t gssapi_context,
gss_name_t gss_client_name, gss_name_t gss_client_name,
DATA_BLOB *pac_data); 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]); 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]); bool gensec_gssapi_parse_krb5_wrap(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, DATA_BLOB *ticket, uint8_t tok_id[2]);

View File

@ -66,18 +66,6 @@ typedef struct {
#endif /* defined(HAVE_MAGIC_IN_KRB5_ADDRESS) && defined(HAVE_ADDRTYPE_IN_KRB5_ADDRESS) */ #endif /* defined(HAVE_MAGIC_IN_KRB5_ADDRESS) && defined(HAVE_ADDRTYPE_IN_KRB5_ADDRESS) */
} smb_krb5_addresses; } 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 */ #ifdef HAVE_KRB5_KEYTAB_ENTRY_KEY /* MIT */
#define KRB5_KT_KEY(k) (&(k)->key) #define KRB5_KT_KEY(k) (&(k)->key)
#elif HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK /* Heimdal */ #elif HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK /* Heimdal */

View File

@ -35,26 +35,6 @@
#include "smb_krb5.h" #include "smb_krb5.h"
#include "gse_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); static char *gse_errstr(TALLOC_CTX *mem_ctx, OM_uint32 maj, OM_uint32 min);
struct gse_context { struct gse_context {
@ -563,96 +543,6 @@ done:
return errstr; 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, static size_t gse_get_signature_length(struct gse_context *gse_ctx,
bool seal, size_t payload_size) bool seal, size_t payload_size)
{ {
@ -1125,8 +1015,8 @@ static bool gensec_gse_have_feature(struct gensec_security *gensec_security,
return false; return false;
} }
status = gse_get_session_key(talloc_tos(), status = gssapi_get_session_key(talloc_tos(),
gse_ctx, NULL, &keytype); gse_ctx->gssapi_context, NULL, &keytype);
/* /*
* We should do a proper sig on the mechListMic unless * We should do a proper sig on the mechListMic unless
* we know we have to be backwards compatible with * 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, talloc_get_type_abort(gensec_security->private_data,
struct gse_context); 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 /* Get some basic (and authorization) information about the user on

View File

@ -1229,6 +1229,7 @@ static bool gensec_gssapi_have_feature(struct gensec_security *gensec_security,
} }
if (feature & GENSEC_FEATURE_NEW_SPNEGO) { if (feature & GENSEC_FEATURE_NEW_SPNEGO) {
NTSTATUS status; NTSTATUS status;
uint32_t keytype;
if (!(gensec_gssapi_state->gss_got_flags & GSS_C_INTEG_FLAG)) { if (!(gensec_gssapi_state->gss_got_flags & GSS_C_INTEG_FLAG)) {
return false; return false;
@ -1241,16 +1242,27 @@ static bool gensec_gssapi_have_feature(struct gensec_security *gensec_security,
return false; return false;
} }
status = gensec_gssapi_init_lucid(gensec_gssapi_state); status = gssapi_get_session_key(gensec_gssapi_state,
if (!NT_STATUS_IS_OK(status)) { gensec_gssapi_state->gssapi_context, NULL, &keytype);
return false; /*
* 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 true;
if (gensec_gssapi_state->lucid->protocol == 1) {
return true;
}
return false;
} }
/* We can always do async (rather than strict request/reply) packets. */ /* We can always do async (rather than strict request/reply) packets. */
if (feature & GENSEC_FEATURE_ASYNC_REPLIES) { 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 struct gensec_gssapi_state *gensec_gssapi_state
= talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state); = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
OM_uint32 maj_stat, min_stat; return gssapi_get_session_key(mem_ctx, gensec_gssapi_state->gssapi_context, session_key, NULL);
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;
} }
/* Get some basic (and authorization) information about the user on /* Get some basic (and authorization) information about the user on