summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2012-02-17 13:36:35 +1100
committerAndrew Bartlett <abartlet@samba.org>2012-02-17 17:36:38 +1100
commit674278d5b0d68e96d68f7beab2289a502efa6bc4 (patch)
tree2e34f2f291f6dc00cc284554eb74c665adbe8f4b
parenta315350341d7090402fe8fe2991d18fa530d2398 (diff)
downloadsamba-674278d5b0d68e96d68f7beab2289a502efa6bc4.tar.gz
samba-674278d5b0d68e96d68f7beab2289a502efa6bc4.tar.bz2
samba-674278d5b0d68e96d68f7beab2289a502efa6bc4.zip
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
-rw-r--r--auth/kerberos/gssapi_pac.c113
-rw-r--r--libcli/auth/krb5_wrap.h17
-rw-r--r--source3/include/smb_krb5.h12
-rw-r--r--source3/librpc/crypto/gse.c116
-rw-r--r--source4/auth/gensec/gensec_gssapi.c55
5 files changed, 155 insertions, 158 deletions
diff --git a/auth/kerberos/gssapi_pac.c b/auth/kerberos/gssapi_pac.c
index 70bc9e576a..d0de11efdf 100644
--- a/auth/kerberos/gssapi_pac.c
+++ b/auth/kerberos/gssapi_pac.c
@@ -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
diff --git a/libcli/auth/krb5_wrap.h b/libcli/auth/krb5_wrap.h
index 814c427a56..01ea6acd07 100644
--- a/libcli/auth/krb5_wrap.h
+++ b/libcli/auth/krb5_wrap.h
@@ -24,6 +24,18 @@
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]);
diff --git a/source3/include/smb_krb5.h b/source3/include/smb_krb5.h
index bc9996c541..152652512d 100644
--- a/source3/include/smb_krb5.h
+++ b/source3/include/smb_krb5.h
@@ -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 */
diff --git a/source3/librpc/crypto/gse.c b/source3/librpc/crypto/gse.c
index d8f3af0897..1ce3761ae7 100644
--- a/source3/librpc/crypto/gse.c
+++ b/source3/librpc/crypto/gse.c
@@ -35,26 +35,6 @@
#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
diff --git a/source4/auth/gensec/gensec_gssapi.c b/source4/auth/gensec/gensec_gssapi.c
index 7f504c5a0f..b2729a9bae 100644
--- a/source4/auth/gensec/gensec_gssapi.c
+++ b/source4/auth/gensec/gensec_gssapi.c
@@ -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