From e63b31932441b6213ace55f4e627d098682965c3 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 source4/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 --- source4/heimdal/lib/krb5/krb5_locl.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/source4/heimdal/lib/krb5/krb5_locl.h b/source4/heimdal/lib/krb5/krb5_locl.h index 49c614d5efe..d3360c556ce 100644 --- a/source4/heimdal/lib/krb5/krb5_locl.h +++ b/source4/heimdal/lib/krb5/krb5_locl.h @@ -188,10 +188,6 @@ struct _krb5_krb_auth_data; #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 f11ebd82b4b6e04433907a8fe15d0a8df11fac8a 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 source4/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 [jsutton@samba.org Adapted to older wscript_build file] --- source4/heimdal_build/wscript_build | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/source4/heimdal_build/wscript_build b/source4/heimdal_build/wscript_build index f151788dcfd..396656e0727 100644 --- a/source4/heimdal_build/wscript_build +++ b/source4/heimdal_build/wscript_build @@ -556,8 +556,8 @@ if not bld.CONFIG_SET("USING_SYSTEM_GSSAPI"): HEIMDAL_AUTOPROTO_PRIVATE('lib/gssapi/krb5/gsskrb5-private.h', HEIMDAL_GSSAPI_KRB5_SOURCE) - HEIMDAL_LIBRARY('gssapi', - HEIMDAL_GSSAPI_SPNEGO_SOURCE + HEIMDAL_GSSAPI_KRB5_SOURCE + ''' + HEIMDAL_SUBSYSTEM('gssapi-subsystem', + HEIMDAL_GSSAPI_SPNEGO_SOURCE + HEIMDAL_GSSAPI_KRB5_SOURCE + ''' lib/gssapi/mech/context.c lib/gssapi/mech/gss_krb5.c lib/gssapi/mech/gss_mech_switch.c lib/gssapi/mech/gss_process_context_token.c lib/gssapi/mech/gss_buffer_set.c lib/gssapi/mech/gss_aeap.c lib/gssapi/mech/gss_add_cred.c lib/gssapi/mech/gss_cred.c @@ -582,10 +582,16 @@ if not bld.CONFIG_SET("USING_SYSTEM_GSSAPI"): lib/gssapi/mech/gss_set_cred_option.c lib/gssapi/mech/gss_pseudo_random.c ../heimdal_build/gssapi-glue.c''', includes='../heimdal/lib/gssapi ../heimdal/lib/gssapi/gssapi ../heimdal/lib/gssapi/spnego ../heimdal/lib/gssapi/krb5 ../heimdal/lib/gssapi/mech', deps='hcrypto asn1 HEIMDAL_SPNEGO_ASN1 HEIMDAL_GSSAPI_ASN1 roken krb5 com_err wind', - vnum='2.0.0', - version_script='lib/gssapi/version-script.map', ) + HEIMDAL_LIBRARY('gssapi', + '', + includes='../heimdal/lib/gssapi ../heimdal/lib/gssapi/gssapi ../heimdal/lib/gssapi/spnego ../heimdal/lib/gssapi/krb5 ../heimdal/lib/gssapi/mech', + deps='gssapi-subsystem', + vnum='2.0.0', + version_script='lib/gssapi/version-script.map', + ) + if not bld.CONFIG_SET("USING_SYSTEM_KRB5"): # expand_path.c needs some of the install paths HEIMDAL_SUBSYSTEM('HEIMDAL_CONFIG', -- 2.25.1 From 04e71e8e5398f42c329db2a9a51c7f76a62a18b0 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 [jsutton@samba.org Adapted to lack of 'samba.unittests.auth.sam' test, renamed 'third_party' to 'source4' in paths, defined HEIMDAL_NORETURN_ATTRIBUTE and HEIMDAL_PRINTF_ATTRIBUTE to fix compiler error] [abartlet@samba.org backported to 4.12 required fixing merge conflicts in wscript_build subsystem conversion (different deps) and tests.py test addition (unrelated changes in context)] --- selftest/knownfail.d/heimdal-des-overflow | 9 + selftest/tests.py | 5 + source4/auth/tests/heimdal_unwrap_des.c | 1247 +++++++++++++++++++++ source4/auth/wscript_build | 21 + 4 files changed, 1282 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 10648b19155..721c36ae4c3 100644 --- a/selftest/tests.py +++ b/selftest/tests.py @@ -46,6 +46,8 @@ have_man_pages_support = ("XSLTPROC_MANPAGES" in config_hash) with_pam = ("WITH_PAM" in config_hash) pam_wrapper_so_path = config_hash["LIBPAM_WRAPPER_SO_PATH"] pam_set_items_so_path = config_hash["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") if have_man_pages_support: @@ -409,5 +411,8 @@ 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"))]) 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..dc31e9d0ad1 --- /dev/null +++ b/source4/auth/tests/heimdal_unwrap_des.c @@ -0,0 +1,1247 @@ +/* + * Unit tests for source4/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" + +#define HEIMDAL_NORETURN_ATTRIBUTE _NORETURN_ +#define HEIMDAL_PRINTF_ATTRIBUTE(x) FORMAT_ATTRIBUTE(x) + +#include "../../../source4/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 b4eefd391b2511d306637a050807c0d68aaaede1 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 source4/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 [jsutton@samba.org Adapted to small differences in comparisons, and removed erroneous duplicate code in conflicting region] --- source4/heimdal/lib/gssapi/krb5/arcfour.c | 24 +++++++---------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/source4/heimdal/lib/gssapi/krb5/arcfour.c b/source4/heimdal/lib/gssapi/krb5/arcfour.c index a61f7686e95..c6b317ff683 100644 --- a/source4/heimdal/lib/gssapi/krb5/arcfour.c +++ b/source4/heimdal/lib/gssapi/krb5/arcfour.c @@ -385,9 +385,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); + cmp = ct_memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4); else - cmp = memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4); + cmp = ct_memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4); memset(SND_SEQ, 0, sizeof(SND_SEQ)); if (cmp != 0) { @@ -656,9 +656,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); + cmp = ct_memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4); else - cmp = memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4); + cmp = ct_memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4); if (cmp != 0) { *minor_status = 0; @@ -1266,19 +1266,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); + cmp = ct_memcmp(&snd_seq[4], "\xff\xff\xff\xff", 4); } else { - cmp = memcmp(&snd_seq[4], "\x00\x00\x00\x00", 4); - } - if (cmp != 0) { - *minor_status = 0; - return GSS_S_BAD_MIC; - } - - if (ctx->more_flags & LOCAL) { - cmp = memcmp(&snd_seq[4], "\xff\xff\xff\xff", 4); - } else { - cmp = memcmp(&snd_seq[4], "\x00\x00\x00\x00", 4); + cmp = ct_memcmp(&snd_seq[4], "\x00\x00\x00\x00", 4); } if (cmp != 0) { *minor_status = 0; @@ -1353,7 +1343,7 @@ _gssapi_unwrap_iov_arcfour(OM_uint32 *minor_status, return GSS_S_FAILURE; } - cmp = memcmp(cksum_data, p0 + 16, 8); /* SGN_CKSUM */ + cmp = ct_memcmp(cksum_data, p0 + 16, 8); /* SGN_CKSUM */ if (cmp != 0) { *minor_status = 0; return GSS_S_BAD_MIC; -- 2.25.1 From 42b23fee3ad77aa29f6f7cbdcf8573756a68f95e 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 source4/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 --- source4/heimdal/lib/gssapi/krb5/unwrap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source4/heimdal/lib/gssapi/krb5/unwrap.c b/source4/heimdal/lib/gssapi/krb5/unwrap.c index b3da35ee9e2..7111a7944fe 100644 --- a/source4/heimdal/lib/gssapi/krb5/unwrap.c +++ b/source4/heimdal/lib/gssapi/krb5/unwrap.c @@ -227,7 +227,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 109a01fba88b641c988a04b14d911929ee82db92 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 source4/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 --- source4/heimdal/lib/gssapi/krb5/unwrap.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/source4/heimdal/lib/gssapi/krb5/unwrap.c b/source4/heimdal/lib/gssapi/krb5/unwrap.c index 7111a7944fe..9639091cb3a 100644 --- a/source4/heimdal/lib/gssapi/krb5/unwrap.c +++ b/source4/heimdal/lib/gssapi/krb5/unwrap.c @@ -180,9 +180,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 @@ -374,9 +375,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 d466a7c156b0797ae9d6eaf49b2f4fd5c9e3e7eb 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 source4/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 --- source4/heimdal/lib/gssapi/krb5/decapsulate.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source4/heimdal/lib/gssapi/krb5/decapsulate.c b/source4/heimdal/lib/gssapi/krb5/decapsulate.c index 86085f56950..4e3fcd659e9 100644 --- a/source4/heimdal/lib/gssapi/krb5/decapsulate.c +++ b/source4/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 73e28ffbce8894c93374feb95c4ed1a87f2e6051 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 source4/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 - source4/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/source4/heimdal/lib/gssapi/krb5/decapsulate.c b/source4/heimdal/lib/gssapi/krb5/decapsulate.c index 4e3fcd659e9..031a621eabc 100644 --- a/source4/heimdal/lib/gssapi/krb5/decapsulate.c +++ b/source4/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 3320c411c5cdf8bb9e4bc945e8bbe0947933d5e1 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 source4/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 ----- source4/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/source4/heimdal/lib/gssapi/krb5/unwrap.c b/source4/heimdal/lib/gssapi/krb5/unwrap.c index 9639091cb3a..70d26a75ccf 100644 --- a/source4/heimdal/lib/gssapi/krb5/unwrap.c +++ b/source4/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; @@ -216,6 +223,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; } @@ -228,6 +237,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 9eb844370966625733f90d17a5d9ad611002567f 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 source4/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 - source4/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/source4/heimdal/lib/gssapi/krb5/decapsulate.c b/source4/heimdal/lib/gssapi/krb5/decapsulate.c index 031a621eabc..d7b75a64222 100644 --- a/source4/heimdal/lib/gssapi/krb5/decapsulate.c +++ b/source4/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 4c272bd20bbd512a63889e25f86506324957d232 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 source4/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 -- source4/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/source4/heimdal/lib/gssapi/krb5/unwrap.c b/source4/heimdal/lib/gssapi/krb5/unwrap.c index 70d26a75ccf..ed8f7d78ffa 100644 --- a/source4/heimdal/lib/gssapi/krb5/unwrap.c +++ b/source4/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; @@ -289,7 +289,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