From 0eaa68d1935236c0a6188ba1ba078db507887e6c Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 12 Oct 2022 13:56:08 +1300 Subject: [PATCH 01/11] CVE-2022-3437 third_party/heimdal: Remove __func__ compatibility workaround As described by the C standard, __func__ is a variable, not a macro. Hence this #ifndef check does not work as intended, and only serves to unconditionally disable __func__. A nonoperating __func__ prevents cmocka operating correctly, so remove this definition. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15134 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett --- third_party/heimdal/lib/krb5/krb5_locl.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/third_party/heimdal/lib/krb5/krb5_locl.h b/third_party/heimdal/lib/krb5/krb5_locl.h index 7045c5bb601..91751c1baba 100644 --- a/third_party/heimdal/lib/krb5/krb5_locl.h +++ b/third_party/heimdal/lib/krb5/krb5_locl.h @@ -204,10 +204,6 @@ extern const char _krb5_wellknown_lkdc[]; #define ALLOC(X, N) (X) = calloc((N), sizeof(*(X))) #define ALLOC_SEQ(X, N) do { (X)->len = (N); ALLOC((X)->val, (N)); } while(0) -#ifndef __func__ -#define __func__ "unknown-function" -#endif - #define krb5_einval(context, argnum) _krb5_einval((context), __func__, (argnum)) #ifndef PATH_SEP -- 2.25.1 From c5dd87f488820e180649e6fd3597bce4ffa24fdc Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 12 Oct 2022 13:55:51 +1300 Subject: [PATCH 02/11] CVE-2022-3437 third_party/heimdal_build: Add gssapi-subsystem subsystem This allows us to access (and so test) functions internal to GSSAPI by depending on this subsystem. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15134 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett --- third_party/heimdal_build/wscript_build | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/third_party/heimdal_build/wscript_build b/third_party/heimdal_build/wscript_build index fc136bc4116..a3bc4792329 100644 --- a/third_party/heimdal_build/wscript_build +++ b/third_party/heimdal_build/wscript_build @@ -633,15 +633,21 @@ if not bld.CONFIG_SET("USING_SYSTEM_GSSAPI"): ../heimdal_build/gssapi-glue.c ''' - HEIMDAL_LIBRARY('gssapi', + HEIMDAL_SUBSYSTEM('gssapi-subsystem', HEIMDAL_GSSAPI_SPNEGO_SOURCE + HEIMDAL_GSSAPI_KRB5_SOURCE + HEIMDAL_GSSAPI_MECH_SOURCE, - includes='../heimdal/lib/gssapi/gssapi ../heimdal/lib/gssapi/spnego ../heimdal/lib/gssapi/krb5 ../heimdal/lib/gssapi/mech ../heimdal/lib/ntlm', - deps='hcrypto asn1 HEIMDAL_SPNEGO_ASN1 HEIMDAL_GSSAPI_ASN1 roken krb5 com_err wind heimbase', - cflags=bld.env.HEIMDAL_UNPICKY_WNO_STRICT_OVERFLOW_CFLAGS, - version_script='lib/gssapi/version-script.map', - ) + includes='../heimdal/lib/gssapi/gssapi ../heimdal/lib/gssapi/spnego ../heimdal/lib/gssapi/krb5 ../heimdal/lib/gssapi/mech ../heimdal/lib/ntlm', + deps='hcrypto asn1 HEIMDAL_SPNEGO_ASN1 HEIMDAL_GSSAPI_ASN1 roken krb5 com_err wind heimbase', + cflags=bld.env.HEIMDAL_UNPICKY_WNO_STRICT_OVERFLOW_CFLAGS, + ) + + HEIMDAL_LIBRARY('gssapi', + '', + includes='../heimdal/lib/gssapi/gssapi ../heimdal/lib/gssapi/spnego ../heimdal/lib/gssapi/krb5 ../heimdal/lib/gssapi/mech ../heimdal/lib/ntlm', + deps='gssapi-subsystem', + version_script='lib/gssapi/version-script.map', + ) if not bld.CONFIG_SET("USING_SYSTEM_KRB5"): # expand_path.c needs some of the install paths -- 2.25.1 From 03eefa45d38ca3eade2018767421bb60ba65d58b Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 12 Oct 2022 13:55:39 +1300 Subject: [PATCH 03/11] CVE-2022-3437 s4/auth/tests: Add unit tests for unwrap_des3() BUG: https://bugzilla.samba.org/show_bug.cgi?id=15134 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett --- selftest/knownfail.d/heimdal-des-overflow | 9 + selftest/tests.py | 5 + source4/auth/tests/heimdal_unwrap_des.c | 1244 +++++++++++++++++++++ source4/auth/wscript_build | 21 + 4 files changed, 1279 insertions(+) create mode 100644 selftest/knownfail.d/heimdal-des-overflow create mode 100644 source4/auth/tests/heimdal_unwrap_des.c diff --git a/selftest/knownfail.d/heimdal-des-overflow b/selftest/knownfail.d/heimdal-des-overflow new file mode 100644 index 00000000000..23acbb43d31 --- /dev/null +++ b/selftest/knownfail.d/heimdal-des-overflow @@ -0,0 +1,9 @@ +^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_dce_style_missing_payload.none +^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_dce_style_with_seal_missing_payload.none +^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_missing_8_bytes.none +^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_missing_payload.none +^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_truncated_header_0.none +^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_truncated_header_1.none +^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_with_padding_truncated_0.none +^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_with_padding_truncated_1.none +^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_with_seal_missing_payload.none diff --git a/selftest/tests.py b/selftest/tests.py index e35c3fff3c1..646956d783a 100644 --- a/selftest/tests.py +++ b/selftest/tests.py @@ -47,6 +47,8 @@ with_pam = ("WITH_PAM" in config_hash) with_elasticsearch_backend = ("HAVE_SPOTLIGHT_BACKEND_ES" in config_hash) pam_wrapper_so_path = config_hash.get("LIBPAM_WRAPPER_SO_PATH") pam_set_items_so_path = config_hash.get("PAM_SET_ITEMS_SO_PATH") +have_heimdal_support = "SAMBA4_USES_HEIMDAL" in config_hash +using_system_gssapi = "USING_SYSTEM_GSSAPI" in config_hash planpythontestsuite("none", "samba.tests.source") planpythontestsuite("none", "samba.tests.source_chars") @@ -432,6 +434,9 @@ plantestsuite("samba.unittests.test_registry_regfio", "none", [os.path.join(bindir(), "default/source3/test_registry_regfio")]) plantestsuite("samba.unittests.test_oLschema2ldif", "none", [os.path.join(bindir(), "default/source4/utils/oLschema2ldif/test_oLschema2ldif")]) +if have_heimdal_support and not using_system_gssapi: + plantestsuite("samba.unittests.auth.heimdal_gensec_unwrap_des", "none", + [valgrindify(os.path.join(bindir(), "test_heimdal_gensec_unwrap_des"))]) if with_elasticsearch_backend: plantestsuite("samba.unittests.mdsparser_es", "none", [os.path.join(bindir(), "default/source3/test_mdsparser_es")] + [configuration]) diff --git a/source4/auth/tests/heimdal_unwrap_des.c b/source4/auth/tests/heimdal_unwrap_des.c new file mode 100644 index 00000000000..fbfe7782e7e --- /dev/null +++ b/source4/auth/tests/heimdal_unwrap_des.c @@ -0,0 +1,1244 @@ +/* + * Unit tests for third_party/heimdal/lib/gssapi/krb5/unwrap.c + * + * Copyright (C) Catalyst.NET Ltd 2022 + * + * 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 . + * + */ + +/* + * from cmocka.c: + * These headers or their equivalents should be included prior to + * including + * this header file. + * + * #include + * #include + * #include + * + * This allows test applications to use custom definitions of C standard + * library functions and types. + * + */ + +#include +#include +#include + +#include + +#include "includes.h" +#include "replace.h" + +#include "../../../third_party/heimdal/lib/gssapi/gssapi/gssapi.h" +#include "gsskrb5_locl.h" + +/****************************************************************************** + * Helper functions + ******************************************************************************/ + +const uint8_t *valid_range_begin; +const uint8_t *valid_range_end; +const uint8_t *invalid_range_end; + +/* + * 'array_len' is the size of the passed in array. 'buffer_len' is the size to + * report in the resulting buffer. + */ +static const gss_buffer_desc get_input_buffer(TALLOC_CTX *mem_ctx, + const uint8_t array[], + const size_t array_len, + const size_t buffer_len) +{ + gss_buffer_desc buf; + + /* Add some padding to catch invalid memory accesses. */ + const size_t padding = 0x100; + const size_t padded_len = array_len + padding; + + uint8_t *data = talloc_size(mem_ctx, padded_len); + assert_non_null(data); + + memcpy(data, array, array_len); + memset(data + array_len, 0, padding); + + assert_in_range(buffer_len, 0, array_len); + + buf.value = data; + buf.length = buffer_len; + + valid_range_begin = buf.value; + valid_range_end = valid_range_begin + buf.length; + invalid_range_end = valid_range_begin + padded_len; + + return buf; +} + +static void assert_mem_in_valid_range(const uint8_t *ptr, const size_t len) +{ + /* Ensure we've set up the range pointers properly. */ + assert_non_null(valid_range_begin); + assert_non_null(valid_range_end); + assert_non_null(invalid_range_end); + + /* + * Ensure the length isn't excessively large (a symptom of integer + * underflow). + */ + assert_in_range(len, 0, 0x1000); + + /* Ensure the memory is in our valid range. */ + assert_in_range(ptr, valid_range_begin, valid_range_end); + assert_in_range(ptr + len, valid_range_begin, valid_range_end); +} + +/* + * This function takes a pointer to volatile to allow it to be called from the + * ct_memcmp() wrapper. + */ +static void assert_mem_outside_invalid_range(const volatile uint8_t *ptr, + const size_t len) +{ + const LargestIntegralType _valid_range_end + = cast_ptr_to_largest_integral_type(valid_range_end); + const LargestIntegralType _invalid_range_end + = cast_ptr_to_largest_integral_type(invalid_range_end); + const LargestIntegralType _ptr = cast_ptr_to_largest_integral_type(ptr); + const LargestIntegralType _len = cast_to_largest_integral_type(len); + + /* Ensure we've set up the range pointers properly. */ + assert_non_null(valid_range_begin); + assert_non_null(valid_range_end); + assert_non_null(invalid_range_end); + + /* + * Ensure the length isn't excessively large (a symptom of integer + * underflow). + */ + assert_in_range(len, 0, 0x1000); + + /* Ensure the memory is outside the invalid range. */ + if (_ptr < _invalid_range_end && _ptr + _len > _valid_range_end) { + fail(); + } +} + +/***************************************************************************** + * wrapped functions + *****************************************************************************/ + +krb5_keyblock dummy_key; + +krb5_error_code __wrap_krb5_auth_con_getlocalsubkey(krb5_context context, + krb5_auth_context auth_context, + krb5_keyblock **keyblock); +krb5_error_code __wrap_krb5_auth_con_getlocalsubkey(krb5_context context, + krb5_auth_context auth_context, + krb5_keyblock **keyblock) +{ + *keyblock = &dummy_key; + return 0; +} + +void __wrap_krb5_free_keyblock(krb5_context context, + krb5_keyblock *keyblock); +void __wrap_krb5_free_keyblock(krb5_context context, + krb5_keyblock *keyblock) +{ + assert_ptr_equal(&dummy_key, keyblock); +} + +struct krb5_crypto_data dummy_crypto; + +krb5_error_code __wrap_krb5_crypto_init(krb5_context context, + const krb5_keyblock *key, + krb5_enctype etype, + krb5_crypto *crypto); +krb5_error_code __wrap_krb5_crypto_init(krb5_context context, + const krb5_keyblock *key, + krb5_enctype etype, + krb5_crypto *crypto) +{ + static const LargestIntegralType etypes[] = {ETYPE_DES3_CBC_NONE, 0}; + + assert_ptr_equal(&dummy_key, key); + assert_in_set(etype, etypes, ARRAY_SIZE(etypes)); + + *crypto = &dummy_crypto; + + return 0; +} + +krb5_error_code __wrap_krb5_decrypt(krb5_context context, + krb5_crypto crypto, + unsigned usage, + void *data, + size_t len, + krb5_data *result); +krb5_error_code __wrap_krb5_decrypt(krb5_context context, + krb5_crypto crypto, + unsigned usage, + void *data, + size_t len, + krb5_data *result) +{ + assert_ptr_equal(&dummy_crypto, crypto); + assert_int_equal(KRB5_KU_USAGE_SEAL, usage); + + assert_mem_in_valid_range(data, len); + + check_expected(len); + check_expected_ptr(data); + + result->data = malloc(len); + assert_non_null(result->data); + result->length = len; + + memcpy(result->data, data, len); + + return 0; +} + +krb5_error_code __wrap_krb5_decrypt_ivec(krb5_context context, + krb5_crypto crypto, + unsigned usage, + void *data, + size_t len, + krb5_data *result, + void *ivec); +krb5_error_code __wrap_krb5_decrypt_ivec(krb5_context context, + krb5_crypto crypto, + unsigned usage, + void *data, + size_t len, + krb5_data *result, + void *ivec) +{ + assert_ptr_equal(&dummy_crypto, crypto); + assert_int_equal(KRB5_KU_USAGE_SEQ, usage); + + assert_mem_in_valid_range(data, len); + + assert_int_equal(8, len); + check_expected_ptr(data); + check_expected_ptr(ivec); + + result->data = malloc(len); + assert_non_null(result->data); + result->length = len; + + memcpy(result->data, data, len); + + return 0; +} + +krb5_error_code __wrap_krb5_verify_checksum(krb5_context context, + krb5_crypto crypto, + krb5_key_usage usage, + void *data, + size_t len, + Checksum *cksum); +krb5_error_code __wrap_krb5_verify_checksum(krb5_context context, + krb5_crypto crypto, + krb5_key_usage usage, + void *data, + size_t len, + Checksum *cksum) +{ + assert_ptr_equal(&dummy_crypto, crypto); + assert_int_equal(KRB5_KU_USAGE_SIGN, usage); + + assert_mem_in_valid_range(data, len); + + check_expected(len); + check_expected_ptr(data); + + assert_non_null(cksum); + assert_int_equal(CKSUMTYPE_HMAC_SHA1_DES3, cksum->cksumtype); + assert_int_equal(20, cksum->checksum.length); + check_expected_ptr(cksum->checksum.data); + + return 0; +} + +krb5_error_code __wrap_krb5_crypto_destroy(krb5_context context, + krb5_crypto crypto); +krb5_error_code __wrap_krb5_crypto_destroy(krb5_context context, + krb5_crypto crypto) +{ + assert_ptr_equal(&dummy_crypto, crypto); + + return 0; +} + + +int __wrap_der_get_length(const unsigned char *p, + size_t len, + size_t *val, + size_t *size); +int __real_der_get_length(const unsigned char *p, + size_t len, + size_t *val, + size_t *size); +int __wrap_der_get_length(const unsigned char *p, + size_t len, + size_t *val, + size_t *size) +{ + assert_mem_in_valid_range(p, len); + + return __real_der_get_length(p, len, val, size); +} + +int __wrap_ct_memcmp(const volatile void * volatile p1, + const volatile void * volatile p2, + size_t len); +int __real_ct_memcmp(const volatile void * volatile p1, + const volatile void * volatile p2, + size_t len); +int __wrap_ct_memcmp(const volatile void * volatile p1, + const volatile void * volatile p2, + size_t len) +{ + assert_mem_outside_invalid_range(p1, len); + assert_mem_outside_invalid_range(p2, len); + + return __real_ct_memcmp(p1, p2, len); +} + +void *__wrap_malloc(size_t size); +void *__real_malloc(size_t size); +void *__wrap_malloc(size_t size) +{ + /* + * Ensure the length isn't excessively large (a symptom of integer + * underflow). + */ + assert_in_range(size, 0, 0x10000); + + return __real_malloc(size); +} + +/***************************************************************************** + * Mock implementations + *****************************************************************************/ + +/* + * Set the globals used by the mocked functions to a known and consistent state + * + */ +static void init_mock_results(TALLOC_CTX *mem_ctx) +{ + dummy_key.keytype = KRB5_ENCTYPE_DES3_CBC_MD5; + dummy_key.keyvalue.data = NULL; + dummy_key.keyvalue.length = 0; + + dummy_crypto = (struct krb5_crypto_data) {0}; + + valid_range_begin = NULL; + valid_range_end = NULL; + invalid_range_end = NULL; +} + +/***************************************************************************** + * Unit test set up and tear down + *****************************************************************************/ + +struct context { + gss_ctx_id_t context_handle; +}; + +static int setup(void **state) { + struct context *ctx = NULL; + krb5_context context = NULL; + OM_uint32 major_status; + OM_uint32 minor_status; + krb5_error_code code; + + ctx = talloc_zero(NULL, struct context); + assert_non_null(ctx); + + init_mock_results(ctx); + + code = _gsskrb5_init(&context); + assert_int_equal(0, code); + + major_status = _gsskrb5_create_ctx(&minor_status, + &ctx->context_handle, + context, + GSS_C_NO_CHANNEL_BINDINGS, + ACCEPTOR_START); + assert_int_equal(GSS_S_COMPLETE, major_status); + + *state = ctx; + return 0; +} + +static int teardown(void **state) { + struct context *ctx = *state; + OM_uint32 major_status; + OM_uint32 minor_status; + + major_status = _gsskrb5_delete_sec_context(&minor_status, + &ctx->context_handle, + GSS_C_NO_BUFFER); + assert_int_equal(GSS_S_COMPLETE, major_status); + + TALLOC_FREE(ctx); + return 0; +} + +/***************************************************************************** + * _gsskrb5_unwrap unit tests + *****************************************************************************/ + +static void test_unwrap_dce_style_missing_payload(void **state) { + struct context *ctx = *state; + OM_uint32 major_status; + OM_uint32 minor_status; + gsskrb5_ctx gss_ctx; + gss_buffer_desc input = {0}; + gss_buffer_desc output = {0}; + int conf_state; + gss_qop_t qop_state; + + /* See RFC 1964 for token format. */ + static const uint8_t data[] = { + 0x60, /* ASN.1 Application tag */ + 0x37, /* total length */ + 0x06, /* OBJECT IDENTIFIER */ + 0x09, /* mech length */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, /* GSS KRB5 mech */ + 0x02, 0x01, /* TOK_ID */ + 0x04, 0x00, /* SGN_ALG (HMAC SHA1 DES3-KD) */ + 0xff, 0xff, /* SEAL_ALG (none) */ + 0xff, 0xff, /* Filler */ + 0xa0, 0xa1, 0xa2, 0xa3, /* encrypted sequence number */ + 0x00, 0x00, 0x00, 0x00, /* sequence number direction (remote) */ + /* checksum */ + 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, + 0xa9, 0xaa, 0xab, 0xac, 0xad, + 0xae, 0xaf, 0xb0, 0xb1, 0xb2, + 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + }; + + input = get_input_buffer(ctx, data, sizeof(data), 22); + + gss_ctx = (gsskrb5_ctx) ctx->context_handle; + gss_ctx->flags |= GSS_C_DCE_STYLE; + + major_status = _gsskrb5_unwrap(&minor_status, + ctx->context_handle, + &input, + &output, + &conf_state, + &qop_state); + assert_int_equal(GSS_S_BAD_MECH, major_status); +} + +static void test_unwrap_dce_style_valid(void **state) { + struct context *ctx = *state; + OM_uint32 major_status; + OM_uint32 minor_status; + gsskrb5_ctx gss_ctx; + gss_buffer_desc input = {0}; + gss_buffer_desc output = {0}; + int conf_state; + gss_qop_t qop_state; + + /* See RFC 1964 for token format. */ + static const uint8_t data[] = { + 0x60, /* ASN.1 Application tag */ + 0x37, /* total length */ + 0x06, /* OBJECT IDENTIFIER */ + 0x09, /* mech length */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, /* GSS KRB5 mech */ + 0x02, 0x01, /* TOK_ID */ + 0x04, 0x00, /* SGN_ALG (HMAC SHA1 DES3-KD) */ + 0xff, 0xff, /* SEAL_ALG (none) */ + 0xff, 0xff, /* Filler */ + 0xa0, 0xa1, 0xa2, 0xa3, /* encrypted sequence number */ + 0x00, 0x00, 0x00, 0x00, /* sequence number direction (remote) */ + /* checksum */ + 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, + 0xa9, 0xaa, 0xab, 0xac, 0xad, + 0xae, 0xaf, 0xb0, 0xb1, 0xb2, + 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + /* unused */ + 0xb8, 0xb9, 0xba, 0xbb, + 0xbc, 0xbd, 0xbe, + 0x00, /* padding byte */ + }; + + input = get_input_buffer(ctx, data, sizeof(data), 57); + + gss_ctx = (gsskrb5_ctx) ctx->context_handle; + gss_ctx->flags |= GSS_C_DCE_STYLE; + + expect_value(__wrap_krb5_decrypt_ivec, data, (uint8_t *)input.value + 21); + expect_memory(__wrap_krb5_decrypt_ivec, ivec, + (uint8_t *)input.value + 29, DES_CBLOCK_LEN); + + expect_value(__wrap_krb5_verify_checksum, len, 16); + expect_value(__wrap_krb5_verify_checksum, data, (uint8_t *)input.value + 41); + expect_memory(__wrap_krb5_verify_checksum, cksum->checksum.data, + (uint8_t *)input.value + 29, 20); + + major_status = _gsskrb5_unwrap(&minor_status, + ctx->context_handle, + &input, + &output, + &conf_state, + &qop_state); + assert_int_equal(GSS_S_COMPLETE, major_status); + + assert_int_equal(0, conf_state); + assert_int_equal(GSS_C_QOP_DEFAULT, qop_state); + + assert_int_equal(output.length, 0); + + major_status = gss_release_buffer(&minor_status, &output); + assert_int_equal(GSS_S_COMPLETE, major_status); +} + +static void test_unwrap_dce_style_with_seal_missing_payload(void **state) { + struct context *ctx = *state; + OM_uint32 major_status; + OM_uint32 minor_status; + gsskrb5_ctx gss_ctx; + gss_buffer_desc input = {0}; + gss_buffer_desc output = {0}; + int conf_state; + gss_qop_t qop_state; + + /* See RFC 1964 for token format. */ + static const uint8_t data[] = { + 0x60, /* ASN.1 Application tag */ + 0x37, /* total length */ + 0x06, /* OBJECT IDENTIFIER */ + 0x09, /* mech length */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, /* GSS KRB5 mech */ + 0x02, 0x01, /* TOK_ID */ + 0x04, 0x00, /* SGN_ALG (HMAC SHA1 DES3-KD) */ + 0x02, 0x00, /* SEAL_ALG (DES3-KD) */ + 0xff, 0xff, /* Filler */ + 0xa0, 0xa1, 0xa2, 0xa3, /* encrypted sequence number */ + 0x00, 0x00, 0x00, 0x00, /* sequence number direction (remote) */ + /* checksum */ + 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, + 0xa9, 0xaa, 0xab, 0xac, 0xad, + 0xae, 0xaf, 0xb0, 0xb1, 0xb2, + 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + }; + + input = get_input_buffer(ctx, data, sizeof(data), 22); + + gss_ctx = (gsskrb5_ctx) ctx->context_handle; + gss_ctx->flags |= GSS_C_DCE_STYLE; + + major_status = _gsskrb5_unwrap(&minor_status, + ctx->context_handle, + &input, + &output, + &conf_state, + &qop_state); + assert_int_equal(GSS_S_BAD_MECH, major_status); +} + +static void test_unwrap_dce_style_with_seal_valid(void **state) { + struct context *ctx = *state; + OM_uint32 major_status; + OM_uint32 minor_status; + gsskrb5_ctx gss_ctx; + gss_buffer_desc input = {0}; + gss_buffer_desc output = {0}; + int conf_state; + gss_qop_t qop_state; + + /* See RFC 1964 for token format. */ + static const uint8_t data[] = { + 0x60, /* ASN.1 Application tag */ + 0x37, /* total length */ + 0x06, /* OBJECT IDENTIFIER */ + 0x09, /* mech length */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, /* GSS KRB5 mech */ + 0x02, 0x01, /* TOK_ID */ + 0x04, 0x00, /* SGN_ALG (HMAC SHA1 DES3-KD) */ + 0x02, 0x00, /* SEAL_ALG (DES3-KD) */ + 0xff, 0xff, /* Filler */ + 0xa0, 0xa1, 0xa2, 0xa3, /* encrypted sequence number */ + 0x00, 0x00, 0x00, 0x00, /* sequence number direction (remote) */ + /* checksum */ + 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, + 0xa9, 0xaa, 0xab, 0xac, 0xad, + 0xae, 0xaf, 0xb0, 0xb1, 0xb2, + 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + /* unused */ + 0xb8, 0xb9, 0xba, 0xbb, + 0xbc, 0xbd, 0xbe, + 0x00, /* padding byte */ + }; + + input = get_input_buffer(ctx, data, sizeof(data), 57); + + gss_ctx = (gsskrb5_ctx) ctx->context_handle; + gss_ctx->flags |= GSS_C_DCE_STYLE; + + expect_value(__wrap_krb5_decrypt, len, 8); + expect_value(__wrap_krb5_decrypt, data, (uint8_t *)input.value + 49); + + expect_value(__wrap_krb5_decrypt_ivec, data, (uint8_t *)input.value + 21); + expect_memory(__wrap_krb5_decrypt_ivec, ivec, + (uint8_t *)input.value + 29, DES_CBLOCK_LEN); + + expect_value(__wrap_krb5_verify_checksum, len, 16); + expect_value(__wrap_krb5_verify_checksum, data, (uint8_t *)input.value + 41); + expect_memory(__wrap_krb5_verify_checksum, cksum->checksum.data, + (uint8_t *)input.value + 29, 20); + + major_status = _gsskrb5_unwrap(&minor_status, + ctx->context_handle, + &input, + &output, + &conf_state, + &qop_state); + assert_int_equal(GSS_S_COMPLETE, major_status); + + assert_int_equal(1, conf_state); + assert_int_equal(GSS_C_QOP_DEFAULT, qop_state); + + assert_int_equal(output.length, 0); + + major_status = gss_release_buffer(&minor_status, &output); + assert_int_equal(GSS_S_COMPLETE, major_status); +} + +static void test_unwrap_missing_8_bytes(void **state) { + struct context *ctx = *state; + OM_uint32 major_status; + OM_uint32 minor_status; + gss_buffer_desc input = {0}; + gss_buffer_desc output = {0}; + int conf_state; + gss_qop_t qop_state; + + /* See RFC 1964 for token format. */ + static const uint8_t data[] = { + 0x60, /* ASN.1 Application tag */ + 0x2f, /* total length */ + 0x06, /* OBJECT IDENTIFIER */ + 0x09, /* mech length */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, /* GSS KRB5 mech */ + 0x02, 0x01, /* TOK_ID */ + 0x04, 0x00, /* SGN_ALG (HMAC SHA1 DES3-KD) */ + 0xff, 0xff, /* SEAL_ALG (none) */ + 0xff, 0xff, /* Filler */ + 0xa0, 0xa1, 0xa2, 0xa3, /* encrypted sequence number */ + 0x00, 0x00, 0x00, 0x00, /* sequence number direction (remote) */ + /* checksum */ + 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, + 0xa9, 0xaa, 0xab, 0xac, 0xad, + 0xae, 0xaf, 0xb0, 0xb1, 0xb2, + 0xb3, 0xb4, 0xb5, 0xb6, 0x00, /* padding byte */ + }; + + input = get_input_buffer(ctx, data, sizeof(data), 49); + + /* + * A fixed unwrap_des3() should fail before these wrappers are called, + * but we want the wrappers to have access to any required values in the + * event that they are called. Specifying WILL_RETURN_ONCE avoids a test + * failure if these values remain unused. + */ + expect_value_count(__wrap_krb5_decrypt_ivec, data, + (uint8_t *)input.value + 21, + WILL_RETURN_ONCE); + expect_memory_count(__wrap_krb5_decrypt_ivec, ivec, + (uint8_t *)input.value + 29, DES_CBLOCK_LEN, + WILL_RETURN_ONCE); + + expect_value_count(__wrap_krb5_verify_checksum, len, 8, WILL_RETURN_ONCE); + expect_value_count(__wrap_krb5_verify_checksum, data, + (uint8_t *)input.value + 41, + WILL_RETURN_ONCE); + expect_memory_count(__wrap_krb5_verify_checksum, cksum->checksum.data, + (uint8_t *)input.value + 29, 20, + WILL_RETURN_ONCE); + + major_status = _gsskrb5_unwrap(&minor_status, + ctx->context_handle, + &input, + &output, + &conf_state, + &qop_state); + assert_int_equal(GSS_S_BAD_MECH, major_status); +} + +static void test_unwrap_missing_payload(void **state) { + struct context *ctx = *state; + OM_uint32 major_status; + OM_uint32 minor_status; + gss_buffer_desc input = {0}; + gss_buffer_desc output = {0}; + int conf_state; + gss_qop_t qop_state; + + /* See RFC 1964 for token format. */ + static const uint8_t data[] = { + 0x60, /* ASN.1 Application tag */ + 0x14, /* total length */ + 0x06, /* OBJECT IDENTIFIER */ + 0x09, /* mech length */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, /* GSS KRB5 mech */ + 0x02, 0x01, /* TOK_ID */ + 0x04, 0x00, /* SGN_ALG (HMAC SHA1 DES3-KD) */ + 0xff, 0xff, /* SEAL_ALG (none) */ + 0xff, 0xff, /* Filler */ + 0x00, 0xa1, 0xa2, 0xa3, /* padding byte / encrypted sequence number */ + 0x00, 0x00, 0x00, 0x00, /* sequence number direction (remote) */ + /* checksum */ + 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, + 0xa9, 0xaa, 0xab, 0xac, 0xad, + 0xae, 0xaf, 0xb0, 0xb1, 0xb2, + 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + }; + + input = get_input_buffer(ctx, data, sizeof(data), 22); + + major_status = _gsskrb5_unwrap(&minor_status, + ctx->context_handle, + &input, + &output, + &conf_state, + &qop_state); + assert_int_equal(GSS_S_BAD_MECH, major_status); +} + +static void test_unwrap_truncated_header_0(void **state) { + struct context *ctx = *state; + OM_uint32 major_status; + OM_uint32 minor_status; + gss_buffer_desc input = {0}; + gss_buffer_desc output = {0}; + int conf_state; + gss_qop_t qop_state; + + /* See RFC 1964 for token format. */ + static const uint8_t data[] = { + 0x60, /* ASN.1 Application tag */ + 0x00, /* total length */ + 0x06, /* OBJECT IDENTIFIER */ + }; + + input = get_input_buffer(ctx, data, sizeof(data), 2); + + major_status = _gsskrb5_unwrap(&minor_status, + ctx->context_handle, + &input, + &output, + &conf_state, + &qop_state); + assert_int_equal(GSS_S_DEFECTIVE_TOKEN, major_status); +} + +static void test_unwrap_truncated_header_1(void **state) { + struct context *ctx = *state; + OM_uint32 major_status; + OM_uint32 minor_status; + gss_buffer_desc input = {0}; + gss_buffer_desc output = {0}; + int conf_state; + gss_qop_t qop_state; + + /* See RFC 1964 for token format. */ + static const uint8_t data[] = { + 0x60, /* ASN.1 Application tag */ + 0x02, /* total length */ + 0x06, /* OBJECT IDENTIFIER */ + 0x09, /* mech length */ + 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, /* GSS KRB5 mech */ + }; + + input = get_input_buffer(ctx, data, sizeof(data), 4); + + major_status = _gsskrb5_unwrap(&minor_status, + ctx->context_handle, + &input, + &output, + &conf_state, + &qop_state); + assert_int_equal(GSS_S_BAD_MECH, major_status); +} + +static void test_unwrap_valid(void **state) { + struct context *ctx = *state; + OM_uint32 major_status; + OM_uint32 minor_status; + gss_buffer_desc input = {0}; + gss_buffer_desc output = {0}; + int conf_state; + gss_qop_t qop_state; + + /* See RFC 1964 for token format. */ + static const uint8_t data[] = { + 0x60, /* ASN.1 Application tag */ + 0x37, /* total length */ + 0x06, /* OBJECT IDENTIFIER */ + 0x09, /* mech length */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, /* GSS KRB5 mech */ + 0x02, 0x01, /* TOK_ID */ + 0x04, 0x00, /* SGN_ALG (HMAC SHA1 DES3-KD) */ + 0xff, 0xff, /* SEAL_ALG (none) */ + 0xff, 0xff, /* Filler */ + 0xa0, 0xa1, 0xa2, 0xa3, /* encrypted sequence number */ + 0x00, 0x00, 0x00, 0x00, /* sequence number direction (remote) */ + /* checksum */ + 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, + 0xa9, 0xaa, 0xab, 0xac, 0xad, + 0xae, 0xaf, 0xb0, 0xb1, 0xb2, + 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + /* unused */ + 0xb8, 0xb9, 0xba, 0xbb, + 0xbc, 0xbd, 0xbe, + 0x00, /* padding byte */ + }; + + input = get_input_buffer(ctx, data, sizeof(data), 57); + + expect_value(__wrap_krb5_decrypt_ivec, data, (uint8_t *)input.value + 21); + expect_memory(__wrap_krb5_decrypt_ivec, ivec, + (uint8_t *)input.value + 29, DES_CBLOCK_LEN); + + expect_value(__wrap_krb5_verify_checksum, len, 16); + expect_value(__wrap_krb5_verify_checksum, data, (uint8_t *)input.value + 41); + expect_memory(__wrap_krb5_verify_checksum, cksum->checksum.data, + (uint8_t *)input.value + 29, 20); + + major_status = _gsskrb5_unwrap(&minor_status, + ctx->context_handle, + &input, + &output, + &conf_state, + &qop_state); + assert_int_equal(GSS_S_COMPLETE, major_status); + + assert_int_equal(0, conf_state); + assert_int_equal(GSS_C_QOP_DEFAULT, qop_state); + + assert_int_equal(output.length, 0); + + major_status = gss_release_buffer(&minor_status, &output); + assert_int_equal(GSS_S_COMPLETE, major_status); +} + +static void test_unwrap_with_padding_truncated_0(void **state) { + struct context *ctx = *state; + OM_uint32 major_status; + OM_uint32 minor_status; + gss_buffer_desc input = {0}; + gss_buffer_desc output = {0}; + int conf_state; + gss_qop_t qop_state; + + /* See RFC 1964 for token format. */ + static const uint8_t data[] = { + 0x60, /* ASN.1 Application tag */ + 0x37, /* total length */ + 0x06, /* OBJECT IDENTIFIER */ + 0x09, /* mech length */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, /* GSS KRB5 mech */ + 0x02, 0x01, /* TOK_ID */ + 0x04, 0x00, /* SGN_ALG (HMAC SHA1 DES3-KD) */ + 0xff, 0xff, /* SEAL_ALG (none) */ + 0xff, 0xff, /* Filler */ + 0xa0, 0xa1, 0xa2, 0xa3, /* encrypted sequence number */ + 0x00, 0x00, 0x00, 0x00, /* sequence number direction (remote) */ + /* checksum */ + 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, + 0xa9, 0xaa, 0xab, 0xac, 0xad, + 0xae, 0xaf, 0xb0, 0xb1, 0xb2, + 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + /* unused */ + 0xb8, 0xb9, 0xba, 0xbb, + 0x04, 0x04, 0x04, 0x04, /* padding bytes */ + }; + + input = get_input_buffer(ctx, data, sizeof(data), 57); + + /* + * A fixed unwrap_des3() should fail before these wrappers are called, + * but we want the wrappers to have access to any required values in the + * event that they are called. Specifying WILL_RETURN_ONCE avoids a test + * failure if these values remain unused. + */ + expect_value_count(__wrap_krb5_decrypt_ivec, data, + (uint8_t *)input.value + 21, + WILL_RETURN_ONCE); + expect_memory_count(__wrap_krb5_decrypt_ivec, ivec, + (uint8_t *)input.value + 29, DES_CBLOCK_LEN, + WILL_RETURN_ONCE); + + expect_value_count(__wrap_krb5_verify_checksum, len, 16, WILL_RETURN_ONCE); + expect_value_count(__wrap_krb5_verify_checksum, data, + (uint8_t *)input.value + 41, + WILL_RETURN_ONCE); + expect_memory_count(__wrap_krb5_verify_checksum, cksum->checksum.data, + (uint8_t *)input.value + 29, 20, + WILL_RETURN_ONCE); + + major_status = _gsskrb5_unwrap(&minor_status, + ctx->context_handle, + &input, + &output, + &conf_state, + &qop_state); + assert_int_equal(GSS_S_BAD_MECH, major_status); +} + +static void test_unwrap_with_padding_truncated_1(void **state) { + struct context *ctx = *state; + OM_uint32 major_status; + OM_uint32 minor_status; + gss_buffer_desc input = {0}; + gss_buffer_desc output = {0}; + int conf_state; + gss_qop_t qop_state; + + /* See RFC 1964 for token format. */ + static const uint8_t data[] = { + 0x60, /* ASN.1 Application tag */ + 0x37, /* total length */ + 0x06, /* OBJECT IDENTIFIER */ + 0x09, /* mech length */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, /* GSS KRB5 mech */ + 0x02, 0x01, /* TOK_ID */ + 0x04, 0x00, /* SGN_ALG (HMAC SHA1 DES3-KD) */ + 0xff, 0xff, /* SEAL_ALG (none) */ + 0xff, 0xff, /* Filler */ + 0x00, 0xa1, 0xa2, 0xa3, /* padding byte / encrypted sequence number */ + 0x00, 0x00, 0x00, 0x00, /* sequence number direction (remote) */ + /* checksum */ + 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, + 0xa9, 0xaa, 0xab, 0xac, 0xad, + 0xae, 0xaf, 0xb0, 0xb1, 0xb2, + 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + /* padding bytes */ + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + }; + + input = get_input_buffer(ctx, data, sizeof(data), 57); + + /* + * A fixed unwrap_des3() should fail before these wrappers are called, + * but we want the wrappers to have access to any required values in the + * event that they are called. Specifying WILL_RETURN_ONCE avoids a test + * failure if these values remain unused. + */ + expect_value_count(__wrap_krb5_decrypt_ivec, data, + (uint8_t *)input.value + 21, + WILL_RETURN_ONCE); + expect_memory_count(__wrap_krb5_decrypt_ivec, ivec, + (uint8_t *)input.value + 29, DES_CBLOCK_LEN, + WILL_RETURN_ONCE); + + expect_value_count(__wrap_krb5_verify_checksum, len, 16, WILL_RETURN_ONCE); + expect_value_count(__wrap_krb5_verify_checksum, data, + (uint8_t *)input.value + 41, + WILL_RETURN_ONCE); + expect_memory_count(__wrap_krb5_verify_checksum, cksum->checksum.data, + (uint8_t *)input.value + 29, 20, + WILL_RETURN_ONCE); + + major_status = _gsskrb5_unwrap(&minor_status, + ctx->context_handle, + &input, + &output, + &conf_state, + &qop_state); + assert_int_equal(GSS_S_BAD_MECH, major_status); +} + +static void test_unwrap_with_padding_valid(void **state) { + struct context *ctx = *state; + OM_uint32 major_status; + OM_uint32 minor_status; + gss_buffer_desc input = {0}; + gss_buffer_desc output = {0}; + int conf_state; + gss_qop_t qop_state; + + /* See RFC 1964 for token format. */ + static const uint8_t data[] = { + 0x60, /* ASN.1 Application tag */ + 0x3f, /* total length */ + 0x06, /* OBJECT IDENTIFIER */ + 0x09, /* mech length */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, /* GSS KRB5 mech */ + 0x02, 0x01, /* TOK_ID */ + 0x04, 0x00, /* SGN_ALG (HMAC SHA1 DES3-KD) */ + 0xff, 0xff, /* SEAL_ALG (none) */ + 0xff, 0xff, /* Filler */ + 0xa0, 0xa1, 0xa2, 0xa3, /* encrypted sequence number */ + 0x00, 0x00, 0x00, 0x00, /* sequence number direction (remote) */ + /* checksum */ + 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, + 0xa9, 0xaa, 0xab, 0xac, 0xad, + 0xae, 0xaf, 0xb0, 0xb1, 0xb2, + 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + /* unused */ + 0xb8, 0xb9, 0xba, 0xbb, + 0xbc, 0xbd, 0xbe, 0xbf, + /* padding bytes */ + 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, + }; + + input = get_input_buffer(ctx, data, sizeof(data), 65); + + expect_value(__wrap_krb5_decrypt_ivec, data, (uint8_t *)input.value + 21); + expect_memory(__wrap_krb5_decrypt_ivec, ivec, + (uint8_t *)input.value + 29, DES_CBLOCK_LEN); + + expect_value(__wrap_krb5_verify_checksum, len, 24); + expect_value(__wrap_krb5_verify_checksum, data, (uint8_t *)input.value + 41); + expect_memory(__wrap_krb5_verify_checksum, cksum->checksum.data, + (uint8_t *)input.value + 29, 20); + + major_status = _gsskrb5_unwrap(&minor_status, + ctx->context_handle, + &input, + &output, + &conf_state, + &qop_state); + assert_int_equal(GSS_S_COMPLETE, major_status); + + assert_int_equal(0, conf_state); + assert_int_equal(GSS_C_QOP_DEFAULT, qop_state); + + assert_int_equal(output.length, 0); + + major_status = gss_release_buffer(&minor_status, &output); + assert_int_equal(GSS_S_COMPLETE, major_status); +} + +static void test_unwrap_with_seal_empty_token_valid(void **state) { + struct context *ctx = *state; + OM_uint32 major_status; + OM_uint32 minor_status; + gss_buffer_desc input = {0}; + gss_buffer_desc output = {0}; + int conf_state; + gss_qop_t qop_state; + + /* See RFC 1964 for token format. */ + static const uint8_t data[] = { + 0x60, /* ASN.1 Application tag */ + 0x37, /* total length */ + 0x06, /* OBJECT IDENTIFIER */ + 0x09, /* mech length */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, /* GSS KRB5 mech */ + 0x02, 0x01, /* TOK_ID */ + 0x04, 0x00, /* SGN_ALG (HMAC SHA1 DES3-KD) */ + 0x02, 0x00, /* SEAL_ALG (DES3-KD) */ + 0xff, 0xff, /* Filler */ + 0xa0, 0xa1, 0xa2, 0xa3, /* encrypted sequence number */ + 0x00, 0x00, 0x00, 0x00, /* sequence number direction (remote) */ + /* checksum */ + 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, + 0xa9, 0xaa, 0xab, 0xac, 0xad, + 0xae, 0xaf, 0xb0, 0xb1, 0xb2, + 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + /* unused */ + 0xb8, 0xb9, 0xba, 0xbb, + 0xbc, 0xbd, 0xbe, + 0x00, /* padding byte */ + }; + + input = get_input_buffer(ctx, data, sizeof(data), 57); + + expect_value(__wrap_krb5_decrypt, len, 8); + expect_value(__wrap_krb5_decrypt, data, (uint8_t *)input.value + 49); + + expect_value(__wrap_krb5_decrypt_ivec, data, (uint8_t *)input.value + 21); + expect_memory(__wrap_krb5_decrypt_ivec, ivec, + (uint8_t *)input.value + 29, DES_CBLOCK_LEN); + + expect_value(__wrap_krb5_verify_checksum, len, 16); + expect_value(__wrap_krb5_verify_checksum, data, (uint8_t *)input.value + 41); + expect_memory(__wrap_krb5_verify_checksum, cksum->checksum.data, + (uint8_t *)input.value + 29, 20); + + major_status = _gsskrb5_unwrap(&minor_status, + ctx->context_handle, + &input, + &output, + &conf_state, + &qop_state); + assert_int_equal(GSS_S_COMPLETE, major_status); + + assert_int_equal(1, conf_state); + assert_int_equal(GSS_C_QOP_DEFAULT, qop_state); + + assert_int_equal(output.length, 0); + + major_status = gss_release_buffer(&minor_status, &output); + assert_int_equal(GSS_S_COMPLETE, major_status); +} + +static void test_unwrap_with_seal_missing_payload(void **state) { + struct context *ctx = *state; + OM_uint32 major_status; + OM_uint32 minor_status; + gss_buffer_desc input = {0}; + gss_buffer_desc output = {0}; + int conf_state; + gss_qop_t qop_state; + + /* See RFC 1964 for token format. */ + static const uint8_t data[] = { + 0x60, /* ASN.1 Application tag */ + 0x14, /* total length */ + 0x06, /* OBJECT IDENTIFIER */ + 0x09, /* mech length */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, /* GSS KRB5 mech */ + 0x02, 0x01, /* TOK_ID */ + 0x04, 0x00, /* SGN_ALG (HMAC SHA1 DES3-KD) */ + 0x02, 0x00, /* SEAL_ALG (DES3-KD) */ + 0xff, 0xff, /* Filler */ + 0xa0, 0xa1, 0xa2, 0xa3, /* encrypted sequence number */ + 0x00, 0x00, 0x00, 0x00, /* sequence number direction (remote) */ + /* checksum */ + 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, + 0xa9, 0xaa, 0xab, 0xac, 0xad, + 0xae, 0xaf, 0xb0, 0xb1, 0xb2, + 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + }; + + input = get_input_buffer(ctx, data, sizeof(data), 22); + + major_status = _gsskrb5_unwrap(&minor_status, + ctx->context_handle, + &input, + &output, + &conf_state, + &qop_state); + assert_int_equal(GSS_S_BAD_MECH, major_status); +} + +static void test_unwrap_with_seal_valid(void **state) { + struct context *ctx = *state; + OM_uint32 major_status; + OM_uint32 minor_status; + gss_buffer_desc input = {0}; + gss_buffer_desc output = {0}; + int conf_state; + gss_qop_t qop_state; + + /* See RFC 1964 for token format. */ + static const uint8_t data[] = { + 0x60, /* ASN.1 Application tag */ + 0x3e, /* total length */ + 0x06, /* OBJECT IDENTIFIER */ + 0x09, /* mech length */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, /* GSS KRB5 mech */ + 0x02, 0x01, /* TOK_ID */ + 0x04, 0x00, /* SGN_ALG (HMAC SHA1 DES3-KD) */ + 0x02, 0x00, /* SEAL_ALG (DES3-KD) */ + 0xff, 0xff, /* Filler */ + 0xa0, 0xa1, 0xa2, 0xa3, /* encrypted sequence number */ + 0x00, 0x00, 0x00, 0x00, /* sequence number direction (remote) */ + /* checksum */ + 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, + 0xa9, 0xaa, 0xab, 0xac, 0xad, + 0xae, 0xaf, 0xb0, 0xb1, 0xb2, + 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + /* unused */ + 0xb8, 0xb9, 0xba, 0xbb, + 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, + 0xc4, 0xc5, + 0x00, /* padding byte */ + }; + + input = get_input_buffer(ctx, data, sizeof(data), 64); + + expect_value(__wrap_krb5_decrypt, len, 15); + expect_value(__wrap_krb5_decrypt, data, (uint8_t *)input.value + 49); + + expect_value(__wrap_krb5_decrypt_ivec, data, (uint8_t *)input.value + 21); + expect_memory(__wrap_krb5_decrypt_ivec, ivec, + (uint8_t *)input.value + 29, DES_CBLOCK_LEN); + + expect_value(__wrap_krb5_verify_checksum, len, 23); + expect_value(__wrap_krb5_verify_checksum, data, (uint8_t *)input.value + 41); + expect_memory(__wrap_krb5_verify_checksum, cksum->checksum.data, + (uint8_t *)input.value + 29, 20); + + major_status = _gsskrb5_unwrap(&minor_status, + ctx->context_handle, + &input, + &output, + &conf_state, + &qop_state); + assert_int_equal(GSS_S_COMPLETE, major_status); + + assert_int_equal(1, conf_state); + assert_int_equal(GSS_C_QOP_DEFAULT, qop_state); + + assert_int_equal(output.length, 7); + assert_memory_equal((uint8_t *)input.value + 57, output.value, output.length); + + major_status = gss_release_buffer(&minor_status, &output); + assert_int_equal(GSS_S_COMPLETE, major_status); +} + +int main(int argc, const char **argv) +{ + static const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown( + test_unwrap_dce_style_missing_payload, setup, teardown), + cmocka_unit_test_setup_teardown( + test_unwrap_dce_style_valid, setup, teardown), + cmocka_unit_test_setup_teardown( + test_unwrap_dce_style_with_seal_missing_payload, setup, teardown), + cmocka_unit_test_setup_teardown( + test_unwrap_dce_style_with_seal_valid, setup, teardown), + cmocka_unit_test_setup_teardown( + test_unwrap_missing_8_bytes, setup, teardown), + cmocka_unit_test_setup_teardown( + test_unwrap_missing_payload, setup, teardown), + cmocka_unit_test_setup_teardown( + test_unwrap_truncated_header_0, setup, teardown), + cmocka_unit_test_setup_teardown( + test_unwrap_truncated_header_1, setup, teardown), + cmocka_unit_test_setup_teardown( + test_unwrap_valid, setup, teardown), + cmocka_unit_test_setup_teardown( + test_unwrap_with_padding_truncated_0, setup, teardown), + cmocka_unit_test_setup_teardown( + test_unwrap_with_padding_truncated_1, setup, teardown), + cmocka_unit_test_setup_teardown( + test_unwrap_with_padding_valid, setup, teardown), + cmocka_unit_test_setup_teardown( + test_unwrap_with_seal_empty_token_valid, setup, teardown), + cmocka_unit_test_setup_teardown( + test_unwrap_with_seal_missing_payload, setup, teardown), + cmocka_unit_test_setup_teardown( + test_unwrap_with_seal_valid, setup, teardown), + }; + + cmocka_set_message_output(CM_OUTPUT_SUBUNIT); + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/source4/auth/wscript_build b/source4/auth/wscript_build index 381a7b19bf0..01b2f280609 100644 --- a/source4/auth/wscript_build +++ b/source4/auth/wscript_build @@ -49,6 +49,27 @@ bld.SAMBA_BINARY('test_kerberos', for_selftest=True ) +bld.SAMBA_BINARY('test_heimdal_gensec_unwrap_des', + source='tests/heimdal_unwrap_des.c', + deps='cmocka talloc gssapi-subsystem', + local_include=False, + for_selftest=True, + enabled=(bld.CONFIG_SET('SAMBA4_USES_HEIMDAL') and + not bld.CONFIG_SET('USING_SYSTEM_GSSAPI')), + ldflags=''' + -Wl,--wrap,ct_memcmp + -Wl,--wrap,der_get_length + -Wl,--wrap,krb5_auth_con_getlocalsubkey + -Wl,--wrap,krb5_crypto_destroy + -Wl,--wrap,krb5_crypto_init + -Wl,--wrap,krb5_decrypt + -Wl,--wrap,krb5_decrypt_ivec + -Wl,--wrap,krb5_free_keyblock + -Wl,--wrap,krb5_verify_checksum + -Wl,--wrap,malloc + ''' +) + pytalloc_util = bld.pyembed_libname('pytalloc-util') pyparam_util = bld.pyembed_libname('pyparam_util') pyldb_util = bld.pyembed_libname('pyldb-util') -- 2.25.1 From e3c314ed69f99db1c797772fbda83820352d5387 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 12 Oct 2022 13:57:13 +1300 Subject: [PATCH 04/11] CVE-2022-3437 third_party/heimdal: Use constant-time memcmp() for arcfour unwrap BUG: https://bugzilla.samba.org/show_bug.cgi?id=15134 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett --- third_party/heimdal/lib/gssapi/krb5/arcfour.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/third_party/heimdal/lib/gssapi/krb5/arcfour.c b/third_party/heimdal/lib/gssapi/krb5/arcfour.c index 8931b32e1c9..5c754bc6d52 100644 --- a/third_party/heimdal/lib/gssapi/krb5/arcfour.c +++ b/third_party/heimdal/lib/gssapi/krb5/arcfour.c @@ -388,9 +388,9 @@ _gssapi_verify_mic_arcfour(OM_uint32 * minor_status, _gsskrb5_decode_be_om_uint32(SND_SEQ, &seq_number); if (context_handle->more_flags & LOCAL) - cmp = (memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4) != 0); + cmp = (ct_memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4) != 0); else - cmp = (memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4) != 0); + cmp = (ct_memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4) != 0); memset_s(SND_SEQ, sizeof(SND_SEQ), 0, sizeof(SND_SEQ)); if (cmp != 0) { @@ -659,9 +659,9 @@ OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status, _gsskrb5_decode_be_om_uint32(SND_SEQ, &seq_number); if (context_handle->more_flags & LOCAL) - cmp = (memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4) != 0); + cmp = (ct_memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4) != 0); else - cmp = (memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4) != 0); + cmp = (ct_memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4) != 0); if (cmp != 0) { *minor_status = 0; @@ -1282,9 +1282,9 @@ _gssapi_unwrap_iov_arcfour(OM_uint32 *minor_status, _gsskrb5_decode_be_om_uint32(snd_seq, &seq_number); if (ctx->more_flags & LOCAL) { - cmp = (memcmp(&snd_seq[4], "\xff\xff\xff\xff", 4) != 0); + cmp = (ct_memcmp(&snd_seq[4], "\xff\xff\xff\xff", 4) != 0); } else { - cmp = (memcmp(&snd_seq[4], "\x00\x00\x00\x00", 4) != 0); + cmp = (ct_memcmp(&snd_seq[4], "\x00\x00\x00\x00", 4) != 0); } if (cmp != 0) { *minor_status = 0; @@ -1359,7 +1359,7 @@ _gssapi_unwrap_iov_arcfour(OM_uint32 *minor_status, return GSS_S_FAILURE; } - cmp = (memcmp(cksum_data, p0 + 16, 8) != 0); /* SGN_CKSUM */ + cmp = (ct_memcmp(cksum_data, p0 + 16, 8) != 0); /* SGN_CKSUM */ if (cmp) { *minor_status = 0; return GSS_S_BAD_MIC; -- 2.25.1 From 9ca9408c5edf807de9fba9f59eabd899c79458a9 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 12 Oct 2022 13:57:55 +1300 Subject: [PATCH 05/11] CVE-2022-3437 third_party/heimdal: Use constant-time memcmp() in unwrap_des3() The surrounding checks all use ct_memcmp(), so this one was presumably meant to as well. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15134 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett --- third_party/heimdal/lib/gssapi/krb5/unwrap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/heimdal/lib/gssapi/krb5/unwrap.c b/third_party/heimdal/lib/gssapi/krb5/unwrap.c index f37b0a653e1..e36491b6f94 100644 --- a/third_party/heimdal/lib/gssapi/krb5/unwrap.c +++ b/third_party/heimdal/lib/gssapi/krb5/unwrap.c @@ -230,7 +230,7 @@ unwrap_des3 if (ret) return ret; - if (memcmp (p, "\x04\x00", 2) != 0) /* HMAC SHA1 DES3_KD */ + if (ct_memcmp (p, "\x04\x00", 2) != 0) /* HMAC SHA1 DES3_KD */ return GSS_S_BAD_SIG; p += 2; if (ct_memcmp (p, "\x02\x00", 2) == 0) { -- 2.25.1 From c944773adc421b3f85a8166fa2d9733e3e9a10c2 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 12 Oct 2022 13:57:42 +1300 Subject: [PATCH 06/11] CVE-2022-3437 third_party/heimdal: Don't pass NULL pointers to memcpy() in DES unwrap BUG: https://bugzilla.samba.org/show_bug.cgi?id=15134 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett --- third_party/heimdal/lib/gssapi/krb5/unwrap.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/third_party/heimdal/lib/gssapi/krb5/unwrap.c b/third_party/heimdal/lib/gssapi/krb5/unwrap.c index e36491b6f94..61ca29156a1 100644 --- a/third_party/heimdal/lib/gssapi/krb5/unwrap.c +++ b/third_party/heimdal/lib/gssapi/krb5/unwrap.c @@ -183,9 +183,10 @@ unwrap_des output_message_buffer->value = malloc(output_message_buffer->length); if(output_message_buffer->length != 0 && output_message_buffer->value == NULL) return GSS_S_FAILURE; - memcpy (output_message_buffer->value, - p + 24, - output_message_buffer->length); + if (output_message_buffer->value != NULL) + memcpy (output_message_buffer->value, + p + 24, + output_message_buffer->length); return GSS_S_COMPLETE; } #endif @@ -377,9 +378,10 @@ unwrap_des3 output_message_buffer->value = malloc(output_message_buffer->length); if(output_message_buffer->length != 0 && output_message_buffer->value == NULL) return GSS_S_FAILURE; - memcpy (output_message_buffer->value, - p + 36, - output_message_buffer->length); + if (output_message_buffer->value != NULL) + memcpy (output_message_buffer->value, + p + 36, + output_message_buffer->length); return GSS_S_COMPLETE; } -- 2.25.1 From e1c2e2836efaa895d817b5611bf908284c3d415d Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 15 Aug 2022 16:53:45 +1200 Subject: [PATCH 07/11] CVE-2022-3437 third_party/heimdal: Avoid undefined behaviour in _gssapi_verify_pad() By decrementing 'pad' only when we know it's safe, we ensure we can't stray backwards past the start of a buffer, which would be undefined behaviour. In the previous version of the loop, 'i' is the number of bytes left to check, and 'pad' is the current byte we're checking. 'pad' was decremented at the end of each loop iteration. If 'i' was 1 (so we checked the final byte), 'pad' could potentially be pointing to the first byte of the input buffer, and the decrement would put it one byte behind the buffer. That would be undefined behaviour. The patch changes it so that 'pad' is the byte we previously checked, which allows us to ensure that we only decrement it when we know we have a byte to check. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15134 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett --- third_party/heimdal/lib/gssapi/krb5/decapsulate.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/third_party/heimdal/lib/gssapi/krb5/decapsulate.c b/third_party/heimdal/lib/gssapi/krb5/decapsulate.c index 86085f56950..4e3fcd659e9 100644 --- a/third_party/heimdal/lib/gssapi/krb5/decapsulate.c +++ b/third_party/heimdal/lib/gssapi/krb5/decapsulate.c @@ -193,13 +193,13 @@ _gssapi_verify_pad(gss_buffer_t wrapped_token, if (wrapped_token->length < 1) return GSS_S_BAD_MECH; - pad = (u_char *)wrapped_token->value + wrapped_token->length - 1; - padlength = *pad; + pad = (u_char *)wrapped_token->value + wrapped_token->length; + padlength = pad[-1]; if (padlength > datalen) return GSS_S_BAD_MECH; - for (i = padlength; i > 0 && *pad == padlength; i--, pad--) + for (i = padlength; i > 0 && *--pad == padlength; i--) ; if (i != 0) return GSS_S_BAD_MIC; -- 2.25.1 From de77f0159873fb0c569c02cee5aa492af8e3f461 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 15 Aug 2022 16:53:55 +1200 Subject: [PATCH 08/11] CVE-2022-3437 third_party/heimdal: Check the result of _gsskrb5_get_mech() We should make sure that the result of 'total_len - mech_len' won't overflow, and that we don't memcmp() past the end of the buffer. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15134 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett --- selftest/knownfail.d/heimdal-des-overflow | 1 - third_party/heimdal/lib/gssapi/krb5/decapsulate.c | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/selftest/knownfail.d/heimdal-des-overflow b/selftest/knownfail.d/heimdal-des-overflow index 23acbb43d31..68b304530db 100644 --- a/selftest/knownfail.d/heimdal-des-overflow +++ b/selftest/knownfail.d/heimdal-des-overflow @@ -3,7 +3,6 @@ ^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_missing_8_bytes.none ^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_missing_payload.none ^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_truncated_header_0.none -^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_truncated_header_1.none ^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_with_padding_truncated_0.none ^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_with_padding_truncated_1.none ^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_with_seal_missing_payload.none diff --git a/third_party/heimdal/lib/gssapi/krb5/decapsulate.c b/third_party/heimdal/lib/gssapi/krb5/decapsulate.c index 4e3fcd659e9..031a621eabc 100644 --- a/third_party/heimdal/lib/gssapi/krb5/decapsulate.c +++ b/third_party/heimdal/lib/gssapi/krb5/decapsulate.c @@ -80,6 +80,10 @@ _gssapi_verify_mech_header(u_char **str, if (mech_len != mech->length) return GSS_S_BAD_MECH; + if (mech_len > total_len) + return GSS_S_BAD_MECH; + if (p - *str > total_len - mech_len) + return GSS_S_BAD_MECH; if (ct_memcmp(p, mech->elements, mech->length) != 0) -- 2.25.1 From d16ac1f4057ec0c26768f04f00c512abf271be7f Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 15 Aug 2022 16:54:23 +1200 Subject: [PATCH 09/11] CVE-2022-3437 third_party/heimdal: Check buffer length against overflow for DES{,3} unwrap BUG: https://bugzilla.samba.org/show_bug.cgi?id=15134 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett --- selftest/knownfail.d/heimdal-des-overflow | 5 ----- third_party/heimdal/lib/gssapi/krb5/unwrap.c | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/selftest/knownfail.d/heimdal-des-overflow b/selftest/knownfail.d/heimdal-des-overflow index 68b304530db..94a49bbee7f 100644 --- a/selftest/knownfail.d/heimdal-des-overflow +++ b/selftest/knownfail.d/heimdal-des-overflow @@ -1,8 +1,3 @@ -^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_dce_style_missing_payload.none -^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_dce_style_with_seal_missing_payload.none -^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_missing_8_bytes.none -^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_missing_payload.none ^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_truncated_header_0.none ^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_with_padding_truncated_0.none ^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_with_padding_truncated_1.none -^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_with_seal_missing_payload.none diff --git a/third_party/heimdal/lib/gssapi/krb5/unwrap.c b/third_party/heimdal/lib/gssapi/krb5/unwrap.c index 61ca29156a1..493165bcfab 100644 --- a/third_party/heimdal/lib/gssapi/krb5/unwrap.c +++ b/third_party/heimdal/lib/gssapi/krb5/unwrap.c @@ -64,6 +64,8 @@ unwrap_des if (IS_DCE_STYLE(context_handle)) { token_len = 22 + 8 + 15; /* 45 */ + if (input_message_buffer->length < token_len) + return GSS_S_BAD_MECH; } else { token_len = input_message_buffer->length; } @@ -76,6 +78,11 @@ unwrap_des if (ret) return ret; + len = (p - (u_char *)input_message_buffer->value) + + 22 + 8; + if (input_message_buffer->length < len) + return GSS_S_BAD_MECH; + if (memcmp (p, "\x00\x00", 2) != 0) return GSS_S_BAD_SIG; p += 2; @@ -219,6 +226,8 @@ unwrap_des3 if (IS_DCE_STYLE(context_handle)) { token_len = 34 + 8 + 15; /* 57 */ + if (input_message_buffer->length < token_len) + return GSS_S_BAD_MECH; } else { token_len = input_message_buffer->length; } @@ -231,6 +240,11 @@ unwrap_des3 if (ret) return ret; + len = (p - (u_char *)input_message_buffer->value) + + 34 + 8; + if (input_message_buffer->length < len) + return GSS_S_BAD_MECH; + if (ct_memcmp (p, "\x04\x00", 2) != 0) /* HMAC SHA1 DES3_KD */ return GSS_S_BAD_SIG; p += 2; -- 2.25.1 From 22dd9072c9f964931db931ee0b638a9799e947ca Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 10 Oct 2022 20:33:09 +1300 Subject: [PATCH 10/11] CVE-2022-3437 third_party/heimdal: Check for overflow in _gsskrb5_get_mech() If len_len is equal to total_len - 1 (i.e. the input consists only of a 0x60 byte and a length), the expression 'total_len - 1 - len_len - 1', used as the 'len' parameter to der_get_length(), will overflow to SIZE_MAX. Then der_get_length() will proceed to read, unconstrained, whatever data follows in memory. Add a check to ensure that doesn't happen. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15134 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett --- selftest/knownfail.d/heimdal-des-overflow | 1 - third_party/heimdal/lib/gssapi/krb5/decapsulate.c | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/selftest/knownfail.d/heimdal-des-overflow b/selftest/knownfail.d/heimdal-des-overflow index 94a49bbee7f..a7416dc61d9 100644 --- a/selftest/knownfail.d/heimdal-des-overflow +++ b/selftest/knownfail.d/heimdal-des-overflow @@ -1,3 +1,2 @@ -^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_truncated_header_0.none ^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_with_padding_truncated_0.none ^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_with_padding_truncated_1.none diff --git a/third_party/heimdal/lib/gssapi/krb5/decapsulate.c b/third_party/heimdal/lib/gssapi/krb5/decapsulate.c index 031a621eabc..d7b75a64222 100644 --- a/third_party/heimdal/lib/gssapi/krb5/decapsulate.c +++ b/third_party/heimdal/lib/gssapi/krb5/decapsulate.c @@ -54,6 +54,8 @@ _gsskrb5_get_mech (const u_char *ptr, e = der_get_length (p, total_len - 1, &len, &len_len); if (e || 1 + len_len + len != total_len) return -1; + if (total_len < 1 + len_len + 1) + return -1; p += len_len; if (*p++ != 0x06) return -1; -- 2.25.1 From 5c31d5beb3bed6b28c8d648d889c47e69c16cc8e Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 12 Oct 2022 13:57:33 +1300 Subject: [PATCH 11/11] CVE-2022-3437 third_party/heimdal: Pass correct length to _gssapi_verify_pad() We later subtract 8 when calculating the length of the output message buffer. If padlength is excessively high, this calculation can underflow and result in a very large positive value. Now we properly constrain the value of padlength so underflow shouldn't be possible. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15134 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett --- selftest/knownfail.d/heimdal-des-overflow | 2 -- third_party/heimdal/lib/gssapi/krb5/unwrap.c | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) delete mode 100644 selftest/knownfail.d/heimdal-des-overflow diff --git a/selftest/knownfail.d/heimdal-des-overflow b/selftest/knownfail.d/heimdal-des-overflow deleted file mode 100644 index a7416dc61d9..00000000000 --- a/selftest/knownfail.d/heimdal-des-overflow +++ /dev/null @@ -1,2 +0,0 @@ -^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_with_padding_truncated_0.none -^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_with_padding_truncated_1.none diff --git a/third_party/heimdal/lib/gssapi/krb5/unwrap.c b/third_party/heimdal/lib/gssapi/krb5/unwrap.c index 493165bcfab..64613698fa4 100644 --- a/third_party/heimdal/lib/gssapi/krb5/unwrap.c +++ b/third_party/heimdal/lib/gssapi/krb5/unwrap.c @@ -124,7 +124,7 @@ unwrap_des } else { /* check pad */ ret = _gssapi_verify_pad(input_message_buffer, - input_message_buffer->length - len, + input_message_buffer->length - len - 8, &padlength); if (ret) return ret; @@ -292,7 +292,7 @@ unwrap_des3 } else { /* check pad */ ret = _gssapi_verify_pad(input_message_buffer, - input_message_buffer->length - len, + input_message_buffer->length - len - 8, &padlength); if (ret) return ret; -- 2.25.1