From 595361dfa974a20c4a44cc11402adbac53ef80dc 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 1e0d0f86a53bea9b7bf22719cbc8ae8d0a8fdc68 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 fb1e466bd4602661880aa612cc74b2b7a2ca7c44 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 2b3de3cdb6d..c9b5ca7b6b2 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") @@ -449,6 +451,9 @@ plantestsuite("samba.unittests.test_oLschema2ldif", "none", [os.path.join(bindir(), "default/source4/utils/oLschema2ldif/test_oLschema2ldif")]) plantestsuite("samba.unittests.auth.sam", "none", [os.path.join(bindir(), "test_auth_sam")]) +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 ff1a61a9566..9b94143ba7c 100644 --- a/source4/auth/wscript_build +++ b/source4/auth/wscript_build @@ -60,6 +60,27 @@ bld.SAMBA_BINARY('test_auth_sam', ''' ) +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 3286b866873a615931784e87541963e9e8f48398 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 e73992be50114d2c48440371d82f019bb4457d15 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 d56d610a324d77429c2bf661a27707afd3710dc9 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 cec4efec572552878252d5ed551f025a9b342c6c 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. 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 512c31c0a1b7000032d4348943b8b8de58bf50b2 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 2b7fe50ad4d3aabeacbe6278dab2b0f4ba69b0fb 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 e5ec9229e0e41577da7f4828370caf17c340df14 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 d0e9a8e98f1bb766ae81c1b0d5a6170cccbee8ea 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