s4:torture: Add rpc netlogon fips test
authorAndreas Schneider <asn@samba.org>
Mon, 26 Jul 2021 08:18:05 +0000 (10:18 +0200)
committerAndreas Schneider <asn@cryptomilk.org>
Tue, 3 Aug 2021 10:18:26 +0000 (10:18 +0000)
Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Autobuild-User(master): Andreas Schneider <asn@cryptomilk.org>
Autobuild-Date(master): Tue Aug  3 10:18:26 UTC 2021 on sn-devel-184

source4/selftest/tests.py
source4/torture/rpc/netlogon_crypto.c [new file with mode: 0644]
source4/torture/rpc/rpc.c
source4/torture/wscript_build

index acf2cf95d35d24c45f0e4a5114dbe9f29b4eddd8..01c190704a0f5b83c857f877a85e5aa580e31a6a 100755 (executable)
@@ -201,7 +201,11 @@ all_rpc_tests = ncalrpc_tests + ncacn_np_tests + ncacn_ip_tcp_tests + slow_ncacn
 rpc_s3only = [
     "rpc.mdssvc",
 ]
-rpc_tests = [x for x in smbtorture4_testsuites("rpc.") if x not in rpc_s3only]
+rpc_fipsonly = [
+    "rpc.fips.netlogon.crypto",
+]
+rpc_exclude = rpc_s3only + rpc_fipsonly
+rpc_tests = [x for x in smbtorture4_testsuites("rpc.") if x not in rpc_exclude]
 auto_rpc_tests = list(filter(lambda t: t not in all_rpc_tests, rpc_tests))
 
 for bindoptions in ["seal,padcheck"] + validate_list + ["bigendian"]:
@@ -636,6 +640,16 @@ if have_gnutls_fips_mode_support:
                   environ={'GNUTLS_FORCE_FIPS_MODE': '1',
                            'OPENSSL_FORCE_FIPS_MODE': '1'})
 
+    plansmbtorture4testsuite('rpc.fips.netlogon.crypto',
+                             'ad_dc_fips',
+                             ['ncacn_np:$SERVER[krb5]',
+                              '-U$USERNAME%$PASSWORD',
+                              '--workgroup=$DOMAIN',
+                              '--client-protection=encrypt'],
+                             'samba4.rpc.fips.netlogon.crypto',
+                             environ={'GNUTLS_FORCE_FIPS_MODE': '1',
+                                      'OPENSSL_FORCE_FIPS_MODE': '1'})
+
 plansmbtorture4testsuite('rpc.echo', "ad_dc_ntvfs", ['ncacn_np:$NETBIOSALIAS', '-U$DOMAIN/$USERNAME%$PASSWORD'], "samba4.rpc.echo against NetBIOS alias")
 
 # Test wbinfo trust auth
diff --git a/source4/torture/rpc/netlogon_crypto.c b/source4/torture/rpc/netlogon_crypto.c
new file mode 100644 (file)
index 0000000..05beb2b
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   test suite for netlogon rpc operations
+
+   Copyright (C) Andrew Tridgell 2003
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003-2004
+   Copyright (C) Tim Potter      2003
+   Copyright (C) Matthias Dieter Wallnöfer            2009-2010
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/replace/system/network.h"
+#include "lib/cmdline/cmdline.h"
+#include "torture/rpc/torture_rpc.h"
+#include "libcli/auth/libcli_auth.h"
+#include "librpc/gen_ndr/ndr_netlogon_c.h"
+#include "param/param.h"
+#include "lib/param/loadparm.h"
+#include "libcli/security/security.h"
+
+#undef strcasecmp
+
+#define TEST_MACHINE_NAME "torturetest"
+
+static bool test_ServerAuth3Crypto(struct dcerpc_pipe *p,
+                                  struct torture_context *tctx,
+                                  uint32_t negotiate_flags,
+                                  struct cli_credentials *machine_credentials,
+                                  bool force_client_rc4)
+{
+       struct netr_ServerReqChallenge r;
+       struct netr_ServerAuthenticate3 a;
+       struct netr_Credential netr_creds1 = {
+               .data = {0},
+       };
+       struct netr_Credential netr_creds2 = {
+               .data = {0},
+       };
+       struct netr_Credential netr_creds3 = {
+               .data = {0},
+       };
+       struct netlogon_creds_CredentialState *creds_state = NULL;
+       struct samr_Password machine_password = {
+               .hash = {0},
+       };
+       const char *machine_name = NULL;
+       const char *plain_pass = NULL;
+       struct dcerpc_binding_handle *b = NULL;
+       uint32_t rid = 0;
+       NTSTATUS status;
+       bool weak_crypto_allowed =
+               (lpcfg_weak_crypto(tctx->lp_ctx) ==
+                SAMBA_WEAK_CRYPTO_ALLOWED);
+
+       if (p == NULL) {
+               return false;
+       }
+       b = p->binding_handle;
+
+       ZERO_STRUCT(r);
+       ZERO_STRUCT(a);
+
+       torture_comment(tctx, "client negotiate_flags=0x%08x\n", negotiate_flags);
+
+       machine_name = cli_credentials_get_workstation(machine_credentials);
+       torture_assert_not_null(tctx, machine_name, "machine name is not set");
+
+       plain_pass = cli_credentials_get_password(machine_credentials);
+       torture_assert_not_null(tctx, plain_pass, "plain_pass is not set");
+
+
+       torture_comment(tctx, "Testing ServerReqChallenge\n");
+
+       r.in.server_name = NULL;
+       r.in.computer_name = machine_name;
+       r.in.credentials = &netr_creds1;
+       r.out.return_credentials = &netr_creds2;
+
+       netlogon_creds_random_challenge(&netr_creds1);
+
+       status = dcerpc_netr_ServerReqChallenge_r(b, tctx, &r);
+       torture_assert_ntstatus_ok(tctx,
+                                  status,
+                                  "ServerReqChallenge failed");
+       torture_assert_ntstatus_ok(tctx,
+                                  r.out.result,
+                                  "ServerReqChallenge failed");
+
+       E_md4hash(plain_pass, machine_password.hash);
+
+       a.in.server_name = NULL;
+       a.in.account_name = talloc_asprintf(tctx, "%s$", machine_name);
+       a.in.secure_channel_type =
+               cli_credentials_get_secure_channel_type(machine_credentials);
+       a.in.computer_name = machine_name;
+       a.in.negotiate_flags = &negotiate_flags;
+       a.in.credentials = &netr_creds3;
+       a.out.return_credentials = &netr_creds3;
+       a.out.negotiate_flags = &negotiate_flags;
+       a.out.rid = &rid;
+
+       if (force_client_rc4) {
+               GNUTLS_FIPS140_SET_LAX_MODE();
+       }
+       creds_state = netlogon_creds_client_init(tctx,
+                                                a.in.account_name,
+                                                a.in.computer_name,
+                                                a.in.secure_channel_type,
+                                                &netr_creds1,
+                                                &netr_creds2,
+                                                &machine_password,
+                                                &netr_creds3,
+                                                negotiate_flags);
+       GNUTLS_FIPS140_SET_STRICT_MODE();
+       /* Test that we fail to encrypt with RC4 */
+       if (creds_state == NULL &&
+           !weak_crypto_allowed && !force_client_rc4 &&
+           (negotiate_flags & NETLOGON_NEG_ARCFOUR)) {
+               return false;
+       }
+       torture_assert_not_null(tctx,
+                               creds_state,
+                               "Failed init netlogon client creds");
+
+
+       torture_comment(tctx, "Testing ServerAuthenticate3\n");
+
+       status = dcerpc_netr_ServerAuthenticate3_r(b, tctx, &a);
+       torture_assert_ntstatus_ok(tctx,
+                                  status,
+                                  "ServerAuthenticate3 failed");
+
+       /* Check that the server denies RC4 */
+       if (!NT_STATUS_IS_OK(a.out.result) &&
+           !weak_crypto_allowed &&
+           force_client_rc4) {
+               torture_assert_ntstatus_equal(tctx,
+                                             a.out.result,
+                                             NT_STATUS_ACCESS_DENIED,
+                                             "Unexpected status code");
+               return false;
+       }
+       torture_assert_ntstatus_ok(tctx,
+                                  a.out.result,
+                                  "ServerAuthenticate3 failed");
+       torture_assert(tctx,
+                      netlogon_creds_client_check(creds_state, &netr_creds3),
+                      "Credential chaining failed");
+
+       torture_comment(tctx,
+                       "server negotiate_flags=0x%08x\n",
+                       negotiate_flags);
+
+       if (!weak_crypto_allowed) {
+               torture_assert(tctx,
+                              (negotiate_flags & NETLOGON_NEG_ARCFOUR) == 0,
+                              "Server should not announce RC4 support");
+       }
+
+       /* Prove that requesting a challenge again won't break it */
+       torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r),
+               "ServerReqChallenge failed");
+       torture_assert_ntstatus_ok(tctx, r.out.result, "ServerReqChallenge failed");
+
+       return true;
+}
+
+
+/* Test that we can successfully authenticate using AES. */
+static bool test_AES_Crypto(struct torture_context *tctx,
+                           struct dcerpc_pipe *p,
+                           struct cli_credentials *machine_credentials)
+{
+       uint32_t negotiate_flags =
+               NETLOGON_NEG_AUTH2_ADS_FLAGS|
+               NETLOGON_NEG_SUPPORTS_AES;
+       bool ok;
+
+       ok = test_ServerAuth3Crypto(p,
+                                   tctx,
+                                   negotiate_flags,
+                                   machine_credentials,
+                                   false);
+       if (!ok) {
+               return false;
+       }
+
+       return true;
+}
+
+/* If we try to use RC4, the client code should fail to encrypt. */
+static bool test_RC4_Crypto_Fail(struct torture_context *tctx,
+                                struct dcerpc_pipe *p,
+                                struct cli_credentials *machine_credentials)
+{
+       uint32_t negotiate_flags =
+               NETLOGON_NEG_AUTH2_ADS_FLAGS|
+               NETLOGON_NEG_ARCFOUR;
+       bool ok;
+
+       ok = test_ServerAuth3Crypto(p,
+                                   tctx,
+                                   negotiate_flags,
+                                   machine_credentials,
+                                   false);
+       if (!ok) {
+               return true;
+       }
+
+       return false;
+}
+
+/*
+ * Enforce the use of RC4 and try to authenticate. The server should fail
+ * in this case as it doesn't allow RC4
+ */
+static bool test_RC4_Crypto_Force(struct torture_context *tctx,
+                                 struct dcerpc_pipe *p,
+                                 struct cli_credentials *machine_credentials)
+{
+       uint32_t negotiate_flags =
+               NETLOGON_NEG_AUTH2_ADS_FLAGS|
+               NETLOGON_NEG_ARCFOUR;
+       bool ok;
+
+       ok = test_ServerAuth3Crypto(p,
+                                   tctx,
+                                   negotiate_flags,
+                                   machine_credentials,
+                                   true);
+       if (!ok) {
+               return true;
+       }
+
+       return false;
+}
+
+struct torture_suite *torture_rpc_netlogon_crypto_fips(TALLOC_CTX *mem_ctx)
+{
+       struct torture_suite *suite = torture_suite_create(mem_ctx,
+                                                          "fips.netlogon.crypto");
+       struct torture_rpc_tcase *tcase = NULL;
+
+       tcase = torture_suite_add_machine_bdc_rpc_iface_tcase(suite,
+                                                             "netlogon",
+                                                             &ndr_table_netlogon,
+                                                             TEST_MACHINE_NAME);
+
+       torture_rpc_tcase_add_test_creds(tcase,
+                                        "test_AES_Crytpo",
+                                        test_AES_Crypto);
+       torture_rpc_tcase_add_test_creds(tcase,
+                                        "test_RC4_Crytpo_Fail",
+                                        test_RC4_Crypto_Fail);
+       torture_rpc_tcase_add_test_creds(tcase,
+                                        "test_RC4_Crytpo_Force",
+                                        test_RC4_Crypto_Force);
+
+       return suite;
+}
index ba10b16990238aa0190a64ac900d14ebc7ade834..b172732409b0f515d6a5c483f0d48c1b9972c588 100644 (file)
@@ -606,6 +606,7 @@ NTSTATUS torture_rpc_init(TALLOC_CTX *ctx)
        torture_suite_add_suite(suite, torture_rpc_netlogon_s3(suite));
        torture_suite_add_suite(suite, torture_rpc_netlogon_admin(suite));
        torture_suite_add_suite(suite, torture_rpc_netlogon_zerologon(suite));
+       torture_suite_add_suite(suite, torture_rpc_netlogon_crypto_fips(suite));
        torture_suite_add_suite(suite, torture_rpc_remote_pac(suite));
        torture_suite_add_simple_test(suite, "samlogon", torture_rpc_samlogon);
        torture_suite_add_simple_test(suite, "samsync", torture_rpc_samsync);
index 3afe3b558ed28b8e40b13201703da7c72a49e8a9..b6014f9c462ee832297f02733dace45557060904 100644 (file)
@@ -121,6 +121,7 @@ bld.SAMBA_MODULE('torture_rpc',
                         rpc/testjoin.c
                         rpc/schannel.c
                         rpc/netlogon.c
+                        rpc/netlogon_crypto.c
                         rpc/remote_pac.c
                         rpc/samlogon.c
                         rpc/samsync.c