From 0d5de7e19c8112821269b4f5a910ee777f35d185 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Sat, 15 Oct 2011 13:17:33 +1100 Subject: gensec: Assert that we have not been subject to a downgrade attack in DCE/RPC clients Because of the calling convention, this is the best place to assert that we have not been subject to a downgrade attack on the negotiated features. (In DCE/RPC, this isn't a negotiation, the client simply specifies the level of protection that is required). Andrew Bartlett (some formatting fixes) Signed-off-by: Stefan Metzmacher --- auth/gensec/gensec.c | 46 +++++++++++++++++++++++++++++++++++++++++++++- auth/gensec/gensec.h | 1 + auth/gensec/gensec_start.c | 2 ++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/auth/gensec/gensec.c b/auth/gensec/gensec.c index 417b05cf06..c0ebc68bb5 100644 --- a/auth/gensec/gensec.c +++ b/auth/gensec/gensec.c @@ -26,6 +26,7 @@ #include "lib/tsocket/tsocket.h" #include "lib/util/tevent_ntstatus.h" #include "auth/gensec/gensec.h" +#include "librpc/rpc/dcerpc.h" /* wrappers for the gensec function pointers @@ -195,7 +196,50 @@ _PUBLIC_ NTSTATUS gensec_session_info(struct gensec_security *gensec_security, _PUBLIC_ NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, const DATA_BLOB in, DATA_BLOB *out) { - return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out); + NTSTATUS status; + + status = gensec_security->ops->update(gensec_security, out_mem_ctx, + in, out); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* + * Because callers using the + * gensec_start_mech_by_auth_type() never call + * gensec_want_feature(), it isn't sensible for them + * to have to call gensec_have_feature() manually, and + * these are not points of negotiation, but are + * asserted by the client + */ + switch (gensec_security->dcerpc_auth_level) { + case DCERPC_AUTH_LEVEL_INTEGRITY: + if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) { + DEBUG(0,("Did not manage to negotiate mandetory feature " + "SIGN for dcerpc auth_level %u\n", + gensec_security->dcerpc_auth_level)); + return NT_STATUS_ACCESS_DENIED; + } + break; + case DCERPC_AUTH_LEVEL_PRIVACY: + if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) { + DEBUG(0,("Did not manage to negotiate mandetory feature " + "SIGN for dcerpc auth_level %u\n", + gensec_security->dcerpc_auth_level)); + return NT_STATUS_ACCESS_DENIED; + } + if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) { + DEBUG(0,("Did not manage to negotiate mandetory feature " + "SEAL for dcerpc auth_level %u\n", + gensec_security->dcerpc_auth_level)); + return NT_STATUS_ACCESS_DENIED; + } + break; + default: + break; + } + + return NT_STATUS_OK; } struct gensec_update_state { diff --git a/auth/gensec/gensec.h b/auth/gensec/gensec.h index 38f2513742..ee87a4da79 100644 --- a/auth/gensec/gensec.h +++ b/auth/gensec/gensec.h @@ -160,6 +160,7 @@ struct gensec_security { enum gensec_role gensec_role; bool subcontext; uint32_t want_features; + uint8_t dcerpc_auth_level; struct tevent_context *event_ctx; struct tsocket_address *local_addr, *remote_addr; struct gensec_settings *settings; diff --git a/auth/gensec/gensec_start.c b/auth/gensec/gensec_start.c index 10fcb67b25..aa609c9b6f 100644 --- a/auth/gensec/gensec_start.c +++ b/auth/gensec/gensec_start.c @@ -547,6 +547,7 @@ _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx, (*gensec_security)->subcontext = true; (*gensec_security)->want_features = parent->want_features; + (*gensec_security)->dcerpc_auth_level = parent->dcerpc_auth_level; (*gensec_security)->event_ctx = parent->event_ctx; (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context); (*gensec_security)->settings = talloc_reference(*gensec_security, parent->settings); @@ -671,6 +672,7 @@ _PUBLIC_ NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_s DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type)); return NT_STATUS_INVALID_PARAMETER; } + gensec_security->dcerpc_auth_level = auth_level; gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE); gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES); if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) { -- cgit