s4:torture/krb5/kdc-heimdal: Automatically determine AS-REP enctype to check against
authorJoseph Sutton <josephsutton@catalyst.net.nz>
Mon, 21 Jun 2021 02:14:48 +0000 (14:14 +1200)
committerStefan Metzmacher <metze@samba.org>
Thu, 1 Jul 2021 17:46:31 +0000 (17:46 +0000)
This enables us to more easily switch to a different algorithm to find
the strongest key in _kdc_find_etype().

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
selftest/knownfail
selftest/knownfail_mit_kdc
source4/torture/krb5/kdc-heimdal.c

index bd3a05c6d8e6310cf1459c56e5a0e3c6a3415738..b2c09e73393c30ddd0fc4ddefafa1f935da3c25e 100644 (file)
 ^samba4.winbind.struct.lookup_name_sid\(ad_member:local\)
 ^samba4.winbind.struct.getdcname\(nt4_member:local\) # Works in other modes, just not against the classic/NT4 DC
 #
-# Differences in our KDC compared to windows
-#
-^samba4.krb5.kdc .*.as-req-pac-request # We should reply to a request for a PAC over UDP with KRB5KRB_ERR_RESPONSE_TOO_BIG unconditionally
-#
 # This will fail against the classic DC, because it requires kerberos
 #
 ^samba4.winbind.pac.*\(nt4_member:local\) # No KDC on a classic DC
 #
 ^samba4.smb.signing.*disabled.*client-protection=off.*\(ad_dc\)
 # fl2000dc doesn't support AES
-^samba4.krb5.kdc.*as-req-aes.*fl2000dc
+^samba4.krb5.kdc.*as-req-aes.fl2000dc
 # nt4_member and ad_member don't support ntlmv1 (not even over SMB1)
 ^samba3.blackbox.smbclient_auth.plain.*option=clientntlmv2auth=no.member.creds.*as.user.*_member
 ^samba3.blackbox.smbclient_auth.plain.*option=clientntlmv2auth=no.*mNT1.member.creds.*as.user.*_member
index db40b0614fafb4a795e70413735a9bd72920b467..fffa5c3cd7e17a4b827f5188d13dd275d87dd195 100644 (file)
@@ -641,3 +641,9 @@ samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_
 ^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_pac_None.fl2008r2dc
 ^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_pac_True.fl2003dc
 ^samba.tests.krb5.as_req_tests.samba.tests.krb5.as_req_tests.AsReqKerberosTests.test_as_req_no_preauth_rc4_pac_True.fl2008r2dc
+# Differences in our KDC compared to windows
+#
+^samba4.krb5.kdc .*.as-req-pac-request # We should reply to a request for a PAC over UDP with KRB5KRB_ERR_RESPONSE_TOO_BIG unconditionally
+#
+# fl2000dc doesn't support AES
+^samba4.krb5.kdc.*as-req-aes.*fl2000dc
index 86b5ec3d72faba85b25cb3607d8090adac26ab8e..acb814b604153a0ef6c009ace1e0b869c84aa2b3 100644 (file)
@@ -204,11 +204,12 @@ static bool torture_check_krb5_error(struct torture_krb5_context *test_context,
 
 static bool torture_check_krb5_as_rep_enctype(struct torture_krb5_context *test_context,
                                              const krb5_data *reply,
-                                             krb5_enctype expected_enctype)
+                                             const krb5_enctype* allowed_enctypes)
 {
        ENCTYPE reply_enctype = { 0 };
        size_t used = 0;
        int rc;
+       int expected_enctype = ETYPE_NULL;
 
        rc = decode_AS_REP(reply->data,
                           reply->length,
@@ -230,8 +231,84 @@ static bool torture_check_krb5_as_rep_enctype(struct torture_krb5_context *test_
                       test_context->as_rep.ticket.enc_part.kvno,
                       "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
 
-       reply_enctype = test_context->as_rep.enc_part.etype;
+       if (test_context->as_req.padata) {
+               /*
+                * If the AS-REQ contains a PA-ENC-TIMESTAMP, then
+                * that encryption type is used to determine the reply
+                * enctype.
+                */
+               int i = 0;
+               const PA_DATA *pa = krb5_find_padata(test_context->as_req.padata->val,
+                                                    test_context->as_req.padata->len,
+                                                    KRB5_PADATA_ENC_TIMESTAMP,
+                                                    &i);
+               if (pa) {
+                       EncryptedData ed;
+                       size_t len;
+                       krb5_error_code ret = decode_EncryptedData(pa->padata_value.data,
+                                                                  pa->padata_value.length,
+                                                                  &ed, &len);
+                       torture_assert_int_equal(test_context->tctx,
+                                                ret,
+                                                0,
+                                                "decode_EncryptedData failed");
+                       expected_enctype = ed.etype;
+                       free_EncryptedData(&ed);
+               }
+       }
+       if (expected_enctype == ETYPE_NULL) {
+               /*
+                * Otherwise, find the strongest enctype contained in
+                * the AS-REQ supported enctypes list.
+                */
+               const krb5_enctype *p = NULL;
+
+               for (p = krb5_kerberos_enctypes(NULL); *p != (krb5_enctype)ETYPE_NULL; ++p) {
+                       int j;
+
+                       if ((*p == (krb5_enctype)ETYPE_AES256_CTS_HMAC_SHA1_96 ||
+                            *p == (krb5_enctype)ETYPE_AES128_CTS_HMAC_SHA1_96) &&
+                           !test_context->as_req.req_body.kdc_options.canonicalize)
+                       {
+                               /*
+                                * AES encryption types are only used here when
+                                * we set the canonicalize flag, as the salt
+                                * needs to match.
+                                */
+                               continue;
+                       }
+
+                       for (j = 0; j < test_context->as_req.req_body.etype.len; ++j) {
+                               krb5_enctype etype = test_context->as_req.req_body.etype.val[j];
+                               if (*p == etype) {
+                                       expected_enctype = etype;
+                                       break;
+                               }
+                       }
+
+                       if (expected_enctype != (krb5_enctype)ETYPE_NULL) {
+                               break;
+                       }
+               }
+       }
+
+       {
+               /* Ensure the enctype to check against is an expected type. */
+               const krb5_enctype *p = NULL;
+               bool found = false;
+               for (p = allowed_enctypes; *p != (krb5_enctype)ETYPE_NULL; ++p) {
+                       if (*p == expected_enctype) {
+                               found = true;
+                               break;
+                       }
+               }
 
+               torture_assert(test_context->tctx,
+                              found,
+                              "Calculated enctype not in allowed list");
+       }
+
+       reply_enctype = test_context->as_rep.enc_part.etype;
        torture_assert_int_equal(test_context->tctx,
                                 reply_enctype, expected_enctype,
                                 "Ticket encrypted with invalid algorithm");
@@ -310,7 +387,7 @@ static bool torture_krb5_post_recv_test(struct torture_krb5_context *test_contex
                if (test_context->packet_count == 0) {
                        ok = torture_check_krb5_error(test_context,
                                                      recv_buf,
-                                                     KRB5KRB_ERR_RESPONSE_TOO_BIG,
+                                                     KRB5KDC_ERR_PREAUTH_REQUIRED,
                                                      false);
                        torture_assert(test_context->tctx,
                                       ok,
@@ -318,7 +395,7 @@ static bool torture_krb5_post_recv_test(struct torture_krb5_context *test_contex
                } else if (test_context->packet_count == 1) {
                        ok = torture_check_krb5_error(test_context,
                                                      recv_buf,
-                                                     KRB5KDC_ERR_PREAUTH_REQUIRED,
+                                                     KRB5KRB_ERR_RESPONSE_TOO_BIG,
                                                      false);
                        torture_assert(test_context->tctx,
                                       ok,
@@ -411,9 +488,13 @@ static bool torture_krb5_post_recv_test(struct torture_krb5_context *test_contex
                                       ok,
                                       "torture_check_krb5_error failed");
                } else {
+                       const krb5_enctype allowed_enctypes[] = {
+                               KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96,
+                               ETYPE_NULL
+                       };
                        ok = torture_check_krb5_as_rep_enctype(test_context,
                                                               recv_buf,
-                                                              KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96);
+                                                              allowed_enctypes);
                        torture_assert(test_context->tctx,
                                       ok,
                                       "torture_check_krb5_as_rep_enctype failed");
@@ -443,9 +524,13 @@ static bool torture_krb5_post_recv_test(struct torture_krb5_context *test_contex
                                       ok,
                                       "torture_check_krb5_error failed");
                } else {
+                       const krb5_enctype allowed_enctypes[] = {
+                               KRB5_ENCTYPE_ARCFOUR_HMAC_MD5,
+                               ETYPE_NULL
+                       };
                        ok = torture_check_krb5_as_rep_enctype(test_context,
                                                               recv_buf,
-                                                              KRB5_ENCTYPE_ARCFOUR_HMAC_MD5);
+                                                              allowed_enctypes);
                        torture_assert(test_context->tctx,
                                       ok,
                                       "torture_check_krb5_as_rep_enctype failed");
@@ -475,9 +560,14 @@ static bool torture_krb5_post_recv_test(struct torture_krb5_context *test_contex
                                       ok,
                                       "torture_check_krb5_error failed");
                } else {
+                       const krb5_enctype allowed_enctypes[] = {
+                               KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96,
+                               KRB5_ENCTYPE_ARCFOUR_HMAC_MD5,
+                               ETYPE_NULL
+                       };
                        ok = torture_check_krb5_as_rep_enctype(test_context,
                                                               recv_buf,
-                                                              KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96);
+                                                              allowed_enctypes);
                        torture_assert(test_context->tctx,
                                       ok,
                                       "torture_check_krb5_as_rep_enctype failed");