gensec: Assert that we have not been subject to a downgrade attack in DCE/RPC clients
authorAndrew Bartlett <abartlet@samba.org>
Sat, 15 Oct 2011 02:17:33 +0000 (13:17 +1100)
committerAndrew Bartlett <abartlet@samba.org>
Tue, 18 Oct 2011 02:13:32 +0000 (13:13 +1100)
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 <metze@samba.org>
auth/gensec/gensec.c
auth/gensec/gensec.h
auth/gensec/gensec_start.c

index 417b05cf063c4dd6dae3ab594058b620e34ea603..c0ebc68bb5edd69c29ff574b4385acb3baee18fb 100644 (file)
@@ -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 {
index 38f2513742512240fcbacc333bbed3d832237014..ee87a4da79e414cff525748c06b03065cdfbbdf3 100644 (file)
@@ -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;
index 10fcb67b255de32a276fb1d9e84279f13789b78b..aa609c9b6fcb14e604af3c9f8a8eb1224678b5a0 100644 (file)
@@ -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) {