From 6881b17bf277c7b4958f66de7af5bdbdecc32eac Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Thu, 3 Feb 2022 07:53:33 +0100 Subject: [PATCH 01/15] bootstrap: Fix CentOS8 runner CentOS8 is EOL since December 31, 2021. The packages move to vault.centos.org. We should migrate to CentOS8 Stream soon. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15193 Signed-off-by: Andreas Schneider Reviewed-by: Alexander Bokovoy Autobuild-User(master): Andreas Schneider Autobuild-Date(master): Thu Feb 3 14:31:01 UTC 2022 on sn-devel-184 [abartlet@samba.org Adapted from commit 0c6554aa0d6812343a8155fca3d7a7993cd5c703 by updating sha1sum] --- .gitlab-ci-main.yml | 2 +- bootstrap/config.py | 9 +++++++++ bootstrap/generated-dists/centos8/bootstrap.sh | 9 +++++++++ bootstrap/sha1sum.txt | 2 +- 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci-main.yml b/.gitlab-ci-main.yml index 125b3901832..c9864707de4 100644 --- a/.gitlab-ci-main.yml +++ b/.gitlab-ci-main.yml @@ -42,7 +42,7 @@ variables: # Set this to the contents of bootstrap/sha1sum.txt # which is generated by bootstrap/template.py --render # - SAMBA_CI_CONTAINER_TAG: dd2b9a1848eed2d200e1a525695e40f06c23d888 + SAMBA_CI_CONTAINER_TAG: fcac3e6e4fef4e0bef6c6e364c35e6e192b23add # # We use the ubuntu1804 image as default as # it matches what we have on sn-devel-184. diff --git a/bootstrap/config.py b/bootstrap/config.py index fd75a771252..326d96ff9d8 100644 --- a/bootstrap/config.py +++ b/bootstrap/config.py @@ -235,6 +235,10 @@ CENTOS8_YUM_BOOTSTRAP = r""" {GENERATED_MARKER} set -xueo pipefail +# CentOS8 is EOL +sed -i -e "s|^mirrorlist=|#mirrorlist=|g" /etc/yum.repos.d/CentOS-* +sed -i -e "s|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g" /etc/yum.repos.d/CentOS-* + yum update -y yum install -y dnf-plugins-core yum install -y epel-release @@ -244,6 +248,11 @@ yum config-manager --set-enabled PowerTools -y || \ yum config-manager --set-enabled powertools -y yum config-manager --set-enabled Devel -y || \ yum config-manager --set-enabled devel -y + +# CentOS8 is EOL +sed -i -e "s|^mirrorlist=|#mirrorlist=|g" /etc/yum.repos.d/CentOS-* +sed -i -e "s|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g" /etc/yum.repos.d/CentOS-* + yum update -y yum install -y \ diff --git a/bootstrap/generated-dists/centos8/bootstrap.sh b/bootstrap/generated-dists/centos8/bootstrap.sh index 60cf3937cf7..db9d0bb8b6c 100755 --- a/bootstrap/generated-dists/centos8/bootstrap.sh +++ b/bootstrap/generated-dists/centos8/bootstrap.sh @@ -7,6 +7,10 @@ set -xueo pipefail +# CentOS8 is EOL +sed -i -e "s|^mirrorlist=|#mirrorlist=|g" /etc/yum.repos.d/CentOS-* +sed -i -e "s|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g" /etc/yum.repos.d/CentOS-* + yum update -y yum install -y dnf-plugins-core yum install -y epel-release @@ -16,6 +20,11 @@ yum config-manager --set-enabled PowerTools -y || \ yum config-manager --set-enabled powertools -y yum config-manager --set-enabled Devel -y || \ yum config-manager --set-enabled devel -y + +# CentOS8 is EOL +sed -i -e "s|^mirrorlist=|#mirrorlist=|g" /etc/yum.repos.d/CentOS-* +sed -i -e "s|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g" /etc/yum.repos.d/CentOS-* + yum update -y yum install -y \ diff --git a/bootstrap/sha1sum.txt b/bootstrap/sha1sum.txt index 11369ced5f7..5716af2a689 100644 --- a/bootstrap/sha1sum.txt +++ b/bootstrap/sha1sum.txt @@ -1 +1 @@ -dd2b9a1848eed2d200e1a525695e40f06c23d888 +fcac3e6e4fef4e0bef6c6e364c35e6e192b23add -- 2.25.1 From ae64b3bfc1823c4efd03f506f6908722e8fa513b Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 6 May 2022 13:29:05 +1200 Subject: [PATCH 02/15] bootstrap: chown the whole cloned repo, not just the subfolders Modern git versions have started to notice the possible security issue. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15193 Signed-off-by: Andrew Bartlett Reviewed-by: Andreas Schneider [abartlet@samba.org adapted from commit c771d197eeebf2b01d46451cc51b698a99502935 with new sha1sum] --- .gitlab-ci-main.yml | 2 +- bootstrap/.gitlab-ci.yml | 2 +- bootstrap/sha1sum.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci-main.yml b/.gitlab-ci-main.yml index c9864707de4..2c7548e41d6 100644 --- a/.gitlab-ci-main.yml +++ b/.gitlab-ci-main.yml @@ -42,7 +42,7 @@ variables: # Set this to the contents of bootstrap/sha1sum.txt # which is generated by bootstrap/template.py --render # - SAMBA_CI_CONTAINER_TAG: fcac3e6e4fef4e0bef6c6e364c35e6e192b23add + SAMBA_CI_CONTAINER_TAG: d541fb969b486082ab6113df5945debfc5ff95c6 # # We use the ubuntu1804 image as default as # it matches what we have on sn-devel-184. diff --git a/bootstrap/.gitlab-ci.yml b/bootstrap/.gitlab-ci.yml index 33534f5f1dd..168272e9872 100644 --- a/bootstrap/.gitlab-ci.yml +++ b/bootstrap/.gitlab-ci.yml @@ -47,7 +47,7 @@ services: diff -u bootstrap/sha1sum.txt /tmp/sha1sum-template.txt # run smoke test with samba-o3 or samba-fuzz docker run --volume $(pwd):${samba_repo_root} --workdir ${samba_repo_root} ${ci_image_name} \ - /bin/bash -c "sudo chown -R samba:samba ./** && export PKG_CONFIG_PATH=/usr/lib64/compat-gnutls34/pkgconfig:/usr/lib64/compat-nettle32/pkgconfig && script/autobuild.py ${SAMBA_CI_TEST_JOB} --verbose --nocleanup --keeplogs --tail --testbase /tmp/samba-testbase" + /bin/bash -c "sudo chown -R samba:samba ${samba_repo_root} && export PKG_CONFIG_PATH=/usr/lib64/compat-gnutls34/pkgconfig:/usr/lib64/compat-nettle32/pkgconfig && script/autobuild.py ${SAMBA_CI_TEST_JOB} --verbose --nocleanup --keeplogs --tail --testbase /tmp/samba-testbase" docker tag ${ci_image_name} ${ci_image_path}:${SAMBA_CI_CONTAINER_TAG} docker tag ${ci_image_name} ${ci_image_path}:${timestamp_tag} # We build all images, but only upload is it's not marked as broken diff --git a/bootstrap/sha1sum.txt b/bootstrap/sha1sum.txt index 5716af2a689..0d8cc2224b2 100644 --- a/bootstrap/sha1sum.txt +++ b/bootstrap/sha1sum.txt @@ -1 +1 @@ -fcac3e6e4fef4e0bef6c6e364c35e6e192b23add +d541fb969b486082ab6113df5945debfc5ff95c6 -- 2.25.1 From 52ed3d07fd5269163b006985e56921cf015a32f9 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Thu, 3 Feb 2022 15:43:54 +0100 Subject: [PATCH 03/15] bootstrap: Migrate to CentOS8 Stream BUG: https://bugzilla.samba.org/show_bug.cgi?id=15193 Signed-off-by: Andreas Schneider Reviewed-by: Alexander Bokovoy Autobuild-User(master): Andreas Schneider Autobuild-Date(master): Fri Feb 4 21:11:40 UTC 2022 on sn-devel-184 [adapted from commit 136ec5bc01e2648bae34a1158f923fbf5a86d561 in the hope of getting lmdb-devel to be available for the CentoS 8 image] --- .gitlab-ci-main.yml | 8 +++---- bootstrap/.gitlab-ci.yml | 2 +- bootstrap/config.py | 22 +++++-------------- bootstrap/generated-dists/Vagrantfile | 10 ++++----- .../{centos8 => centos8s}/Dockerfile | 2 +- .../{centos8 => centos8s}/bootstrap.sh | 12 +--------- .../{centos8 => centos8s}/locale.sh | 0 .../{centos8 => centos8s}/packages.yml | 0 bootstrap/sha1sum.txt | 2 +- 9 files changed, 19 insertions(+), 39 deletions(-) rename bootstrap/generated-dists/{centos8 => centos8s}/Dockerfile (90%) rename bootstrap/generated-dists/{centos8 => centos8s}/bootstrap.sh (79%) rename bootstrap/generated-dists/{centos8 => centos8s}/locale.sh (100%) rename bootstrap/generated-dists/{centos8 => centos8s}/packages.yml (100%) diff --git a/.gitlab-ci-main.yml b/.gitlab-ci-main.yml index 2c7548e41d6..b8bae9b10b7 100644 --- a/.gitlab-ci-main.yml +++ b/.gitlab-ci-main.yml @@ -42,7 +42,7 @@ variables: # Set this to the contents of bootstrap/sha1sum.txt # which is generated by bootstrap/template.py --render # - SAMBA_CI_CONTAINER_TAG: d541fb969b486082ab6113df5945debfc5ff95c6 + SAMBA_CI_CONTAINER_TAG: fbf9c4c8a2055936d4ca279878df7811af46d86d # # We use the ubuntu1804 image as default as # it matches what we have on sn-devel-184. @@ -64,7 +64,7 @@ variables: SAMBA_CI_CONTAINER_IMAGE_fedora33: fedora33 SAMBA_CI_CONTAINER_IMAGE_fedora34: fedora34 SAMBA_CI_CONTAINER_IMAGE_centos7: centos7 - SAMBA_CI_CONTAINER_IMAGE_centos8: centos8 + SAMBA_CI_CONTAINER_IMAGE_centos8s: centos8s include: # The image creation details are specified in a separate file @@ -594,10 +594,10 @@ centos7-samba-o3: # We need a newer GnuTLS version on CentOS7 PKG_CONFIG_PATH: "/usr/lib64/compat-gnutls34/pkgconfig:/usr/lib64/compat-nettle32/pkgconfig" -centos8-samba-o3: +centos8s-samba-o3: extends: .samba-o3-template variables: - SAMBA_CI_JOB_IMAGE: ${SAMBA_CI_CONTAINER_IMAGE_centos8} + SAMBA_CI_JOB_IMAGE: ${SAMBA_CI_CONTAINER_IMAGE_centos8s} fedora33-samba-o3: extends: .samba-o3-template diff --git a/bootstrap/.gitlab-ci.yml b/bootstrap/.gitlab-ci.yml index 168272e9872..58e0642a70d 100644 --- a/bootstrap/.gitlab-ci.yml +++ b/bootstrap/.gitlab-ci.yml @@ -112,7 +112,7 @@ fedora33: fedora34: extends: .build_image_template -centos8: +centos8s: extends: .build_image_template centos7: diff --git a/bootstrap/config.py b/bootstrap/config.py index 326d96ff9d8..164ab306329 100644 --- a/bootstrap/config.py +++ b/bootstrap/config.py @@ -230,28 +230,18 @@ if [ ! -f /usr/bin/python3 ]; then fi """ -CENTOS8_YUM_BOOTSTRAP = r""" +CENTOS8S_YUM_BOOTSTRAP = r""" #!/bin/bash {GENERATED_MARKER} set -xueo pipefail -# CentOS8 is EOL -sed -i -e "s|^mirrorlist=|#mirrorlist=|g" /etc/yum.repos.d/CentOS-* -sed -i -e "s|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g" /etc/yum.repos.d/CentOS-* - yum update -y yum install -y dnf-plugins-core yum install -y epel-release yum -v repolist all -yum config-manager --set-enabled PowerTools -y || \ +yum config-manager --set-enabled powertools -y || \ yum config-manager --set-enabled powertools -y -yum config-manager --set-enabled Devel -y || \ - yum config-manager --set-enabled devel -y - -# CentOS8 is EOL -sed -i -e "s|^mirrorlist=|#mirrorlist=|g" /etc/yum.repos.d/CentOS-* -sed -i -e "s|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g" /etc/yum.repos.d/CentOS-* yum update -y @@ -480,10 +470,10 @@ RPM_DISTS = { 'tracker-devel': '', # do not install } }, - 'centos8': { - 'docker_image': 'centos:8', - 'vagrant_box': 'centos/8', - 'bootstrap': CENTOS8_YUM_BOOTSTRAP, + 'centos8s': { + 'docker_image': 'quay.io/centos/centos:stream8', + 'vagrant_box': 'centos/stream8', + 'bootstrap': CENTOS8S_YUM_BOOTSTRAP, 'replace': { 'lsb-release': 'redhat-lsb', '@development-tools': '"@Development Tools"', # add quotes diff --git a/bootstrap/generated-dists/Vagrantfile b/bootstrap/generated-dists/Vagrantfile index 780320ec7c8..10075800c01 100644 --- a/bootstrap/generated-dists/Vagrantfile +++ b/bootstrap/generated-dists/Vagrantfile @@ -17,11 +17,11 @@ Vagrant.configure("2") do |config| v.vm.provision :shell, path: "centos7/locale.sh" end - config.vm.define "centos8" do |v| - v.vm.box = "centos/8" - v.vm.hostname = "centos8" - v.vm.provision :shell, path: "centos8/bootstrap.sh" - v.vm.provision :shell, path: "centos8/locale.sh" + config.vm.define "centos8s" do |v| + v.vm.box = "centos/stream8" + v.vm.hostname = "centos8s" + v.vm.provision :shell, path: "centos8s/bootstrap.sh" + v.vm.provision :shell, path: "centos8s/locale.sh" end config.vm.define "debian10" do |v| diff --git a/bootstrap/generated-dists/centos8/Dockerfile b/bootstrap/generated-dists/centos8s/Dockerfile similarity index 90% rename from bootstrap/generated-dists/centos8/Dockerfile rename to bootstrap/generated-dists/centos8s/Dockerfile index f6343e9d5a2..1c932f58a94 100644 --- a/bootstrap/generated-dists/centos8/Dockerfile +++ b/bootstrap/generated-dists/centos8s/Dockerfile @@ -3,7 +3,7 @@ # See also bootstrap/config.py # -FROM centos:8 +FROM quay.io/centos/centos:stream8 # pass in with --build-arg while build ARG SHA1SUM diff --git a/bootstrap/generated-dists/centos8/bootstrap.sh b/bootstrap/generated-dists/centos8s/bootstrap.sh similarity index 79% rename from bootstrap/generated-dists/centos8/bootstrap.sh rename to bootstrap/generated-dists/centos8s/bootstrap.sh index db9d0bb8b6c..1111450c400 100755 --- a/bootstrap/generated-dists/centos8/bootstrap.sh +++ b/bootstrap/generated-dists/centos8s/bootstrap.sh @@ -7,23 +7,13 @@ set -xueo pipefail -# CentOS8 is EOL -sed -i -e "s|^mirrorlist=|#mirrorlist=|g" /etc/yum.repos.d/CentOS-* -sed -i -e "s|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g" /etc/yum.repos.d/CentOS-* - yum update -y yum install -y dnf-plugins-core yum install -y epel-release yum -v repolist all -yum config-manager --set-enabled PowerTools -y || \ +yum config-manager --set-enabled powertools -y || \ yum config-manager --set-enabled powertools -y -yum config-manager --set-enabled Devel -y || \ - yum config-manager --set-enabled devel -y - -# CentOS8 is EOL -sed -i -e "s|^mirrorlist=|#mirrorlist=|g" /etc/yum.repos.d/CentOS-* -sed -i -e "s|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g" /etc/yum.repos.d/CentOS-* yum update -y diff --git a/bootstrap/generated-dists/centos8/locale.sh b/bootstrap/generated-dists/centos8s/locale.sh similarity index 100% rename from bootstrap/generated-dists/centos8/locale.sh rename to bootstrap/generated-dists/centos8s/locale.sh diff --git a/bootstrap/generated-dists/centos8/packages.yml b/bootstrap/generated-dists/centos8s/packages.yml similarity index 100% rename from bootstrap/generated-dists/centos8/packages.yml rename to bootstrap/generated-dists/centos8s/packages.yml diff --git a/bootstrap/sha1sum.txt b/bootstrap/sha1sum.txt index 0d8cc2224b2..120d935186d 100644 --- a/bootstrap/sha1sum.txt +++ b/bootstrap/sha1sum.txt @@ -1 +1 @@ -d541fb969b486082ab6113df5945debfc5ff95c6 +fbf9c4c8a2055936d4ca279878df7811af46d86d -- 2.25.1 From 9f658aa5fe2d64780b4cd25a456ae0c6e4b7c2a4 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 6 May 2022 17:53:29 +1200 Subject: [PATCH 04/15] .gitlab-ci: Work around new git restrictions arising from CVE-2022-24765 It was realised that git would run commands found in a git repo (eg from configuration). BUG: https://bugzilla.samba.org/show_bug.cgi?id=15193 Signed-off-by: Andrew Bartlett Reviewed-by: Andreas Schneider (cherry picked from commit dd568490089ae6d5bcf03068bfc4ca6b9103badb) --- .gitlab-ci-main.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab-ci-main.yml b/.gitlab-ci-main.yml index b8bae9b10b7..e0b9b9d20b9 100644 --- a/.gitlab-ci-main.yml +++ b/.gitlab-ci-main.yml @@ -137,6 +137,8 @@ include: - export CXX="ccache c++" - ccache -z -M 500M - ccache -s + # We are already running .gitlab-ci directives from this repo, remove additional checks that break our CI + - git config --global --add safe.directory `pwd` after_script: - mount - df -h -- 2.25.1 From fe1204d9da2c6f761c4dc4421f67057b10eaf430 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 12 Oct 2022 13:56:08 +1300 Subject: [PATCH 05/15] 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 a49a3ac8e082921c2793a073b5991c4693f167ab Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 12 Oct 2022 13:55:51 +1300 Subject: [PATCH 06/15] 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 e91c8ab2eeb..41152192798 100644 --- a/source4/heimdal_build/wscript_build +++ b/source4/heimdal_build/wscript_build @@ -571,8 +571,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 @@ -597,10 +597,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 heimbase', - 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 310bffc085514f9ceba5b3501ddef15807c53809 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 12 Oct 2022 13:55:39 +1300 Subject: [PATCH 07/15] 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] --- 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 c87b41c1a66..1331a6841e0 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") if have_man_pages_support: @@ -429,6 +431,9 @@ plantestsuite("samba.unittests.test_registry_regfio", "none", [os.path.join(bindir(), "default/source3/test_registry_regfio")]) plantestsuite("samba.unittests.test_oLschema2ldif", "none", [os.path.join(bindir(), "default/source4/utils/oLschema2ldif/test_oLschema2ldif")]) +if have_heimdal_support and not using_system_gssapi: + plantestsuite("samba.unittests.auth.heimdal_gensec_unwrap_des", "none", + [valgrindify(os.path.join(bindir(), "test_heimdal_gensec_unwrap_des"))]) if with_elasticsearch_backend: plantestsuite("samba.unittests.mdsparser_es", "none", [os.path.join(bindir(), "default/source3/test_mdsparser_es")] + [configuration]) diff --git a/source4/auth/tests/heimdal_unwrap_des.c b/source4/auth/tests/heimdal_unwrap_des.c new file mode 100644 index 00000000000..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 c22914f845b3eba1c9ad444333f3d044352b7e2c Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 12 Oct 2022 13:57:13 +1300 Subject: [PATCH 08/15] 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 5f6dbf2ab29bcd30c701cab3daecf5a6a53a44cd Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 12 Oct 2022 13:57:55 +1300 Subject: [PATCH 09/15] 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 9f6f1e01aca4f00a5d23127803c81939253e0577 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 12 Oct 2022 13:57:42 +1300 Subject: [PATCH 10/15] 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 5a62eb5734d50fe556934aefa3bac5698372f00e Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 15 Aug 2022 16:53:45 +1200 Subject: [PATCH 11/15] 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 ebac8bf0478e19849f83af6d44b73d7ab3afd25b Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 15 Aug 2022 16:53:55 +1200 Subject: [PATCH 12/15] 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 1aca34515515f2cb00fbf5ad8b9212b319f01836 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 15 Aug 2022 16:54:23 +1200 Subject: [PATCH 13/15] 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 77e0f2febaaf4d6e5e42f8e73a1f8f3c0e4a2985 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Mon, 10 Oct 2022 20:33:09 +1300 Subject: [PATCH 14/15] 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 e9db03736007721e37c4fba847ce4aa0c4520924 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Wed, 12 Oct 2022 13:57:33 +1300 Subject: [PATCH 15/15] 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