Commit ab6f5e915b for openssl.org
commit ab6f5e915b6869ea5d15df14976a1499031b9366
Author: Jakub Zelenka <jakub.zelenka@openssl.foundation>
Date: Fri May 15 13:00:38 2026 +0200
Add apps test for external PSK callbacks
Reviewed-by: Neil Horman <nhorman@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
MergeDate: Thu Jun 11 15:52:36 2026
(Merged from https://github.com/openssl/openssl/pull/31190)
diff --git a/test/recipes/70-test_tlspskext.t b/test/recipes/70-test_tlspskext.t
new file mode 100644
index 0000000000..980aab2cb4
--- /dev/null
+++ b/test/recipes/70-test_tlspskext.t
@@ -0,0 +1,148 @@
+#! /usr/bin/env perl
+# Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the Apache License 2.0 (the "License"). You may not use
+# this file except in compliance with the License. You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+use strict;
+use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file bldtop_dir/;
+use OpenSSL::Test::Utils;
+use TLSProxy::Proxy;
+use TLSProxy::Message;
+use Cwd qw(abs_path);
+
+my $test_name = "test_tlpskext";
+setup($test_name);
+
+plan skip_all => "TLSProxy isn't usable on $^O"
+ if $^O =~ /^(VMS)$/;
+plan skip_all => "$test_name needs the sock feature enabled"
+ if disabled("sock");
+plan skip_all => "No TLS protocols are supported by this OpenSSL build"
+ if alldisabled(available_protocols("tls"));
+plan skip_all => "$test_name needs the module feature enabled"
+ if disabled("module");
+
+$ENV{OPENSSL_MODULES} = abs_path(bldtop_dir("test"));
+
+my $psk = "0102030405060708090a0b0c0d0e0f10";
+
+my $proxy = TLSProxy::Proxy->new(
+ undef,
+ cmdstr(app(["openssl"]), display => 1),
+ srctop_file("apps", "server.pem"),
+ (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE}),
+ have_IPv6()
+);
+
+$proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
+
+my $tls13_disabled = disabled("tls1_3") || (disabled("ec") && disabled("dh"));
+my $tls12_disabled = disabled("tls1_2");
+plan skip_all => "$test_name needs TLSv1.2 or TLSv1.3 enabled"
+ if $tls13_disabled && $tls12_disabled;
+plan tests => 6;
+
+my $psk_ext_in_ch = 0;
+my $psk_ext_in_sh = 0;
+
+SKIP: {
+ skip "TLS 1.3 disabled", 4
+ if disabled("tls1_3") || (disabled("ec") && disabled("dh"));
+
+ my $flags = "-tls1_3 -no_rx_cert_comp";
+
+ # psk_use_session_cb (client) / psk_find_session_cb (server).
+ $proxy->clear();
+ $proxy->clientflags("-psk $psk $flags");
+ $proxy->serverflags("-psk $psk $flags");
+ $proxy->filter(undef);
+ $proxy->start();
+ ok(TLSProxy::Message->success(), "TLS 1.3 PSK connection");
+
+ $proxy->clear();
+ $proxy->clientflags("-psk $psk $flags");
+ $proxy->serverflags("-psk $psk $flags");
+ $psk_ext_in_ch = 0;
+ $proxy->filter(\&check_psk_in_ch);
+ $proxy->start();
+ ok($psk_ext_in_ch, "PSK extension present in TLS 1.3 ClientHello");
+
+ # psk_find_session_cb returns *sess = NULL on mismatch; falls back to cert.
+ $proxy->clear();
+ $proxy->clientflags("-psk $psk -psk_identity other_id $flags");
+ $proxy->serverflags("-psk $psk $flags");
+ $proxy->filter(undef);
+ $proxy->start();
+ ok(TLSProxy::Message->success(),
+ "TLS 1.3 PSK identity mismatch falls back to certificate auth");
+
+ $proxy->clear();
+ $proxy->clientflags("-psk $psk -psk_identity other_id $flags");
+ $proxy->serverflags("-psk $psk $flags");
+ $psk_ext_in_sh = 0;
+ $proxy->filter(\&check_psk_in_sh);
+ $proxy->start();
+ ok(!$psk_ext_in_sh,
+ "No PSK in ServerHello when TLS 1.3 identity mismatches");
+}
+
+SKIP: {
+ skip "TLS 1.2 disabled", 2 if disabled("tls1_2");
+
+ # PSK-AES128-CBC-SHA is required here: TLSProxy's record layer only handles
+ # CBC correctly (it strips IV + padding + MAC as fixed offset bytes).
+ # GCM ciphers use a different wire layout and confuse the decryption stub,
+ # making close_notify detection fail even on a successful connection.
+ my $psk_cipher = "PSK-AES128-CBC-SHA:\@SECLEVEL=0";
+ my $flags = "-tls1_2 -no_rx_cert_comp";
+
+ # psk_client_cb (client) / psk_server_cb (server).
+ $proxy->clear();
+ $proxy->ciphers($psk_cipher);
+ $proxy->cipherc($psk_cipher);
+ $proxy->clientflags("-psk $psk $flags");
+ $proxy->serverflags("-psk $psk $flags");
+ $proxy->filter(undef);
+ $proxy->start();
+ ok(TLSProxy::Message->success(), "TLS 1.2 PSK connection");
+
+ # psk_server_cb accepts regardless of identity and only logs a warning.
+ $proxy->clear();
+ $proxy->ciphers($psk_cipher);
+ $proxy->cipherc($psk_cipher);
+ $proxy->clientflags("-psk $psk -psk_identity other_id $flags");
+ $proxy->serverflags("-psk $psk $flags");
+ $proxy->filter(undef);
+ $proxy->start();
+ ok(TLSProxy::Message->success(),
+ "TLS 1.2 PSK identity mismatch succeeds with warning");
+}
+
+sub check_psk_in_ch
+{
+ my $proxy = shift;
+
+ return if $proxy->flight != 0;
+
+ foreach my $message (@{$proxy->message_list}) {
+ next unless $message->mt == TLSProxy::Message::MT_CLIENT_HELLO;
+ $psk_ext_in_ch = 1
+ if defined ${$message->extension_data}{TLSProxy::Message::EXT_PSK};
+ }
+}
+
+sub check_psk_in_sh
+{
+ my $proxy = shift;
+
+ return if $proxy->flight != 1;
+
+ foreach my $message (@{$proxy->message_list}) {
+ next unless $message->mt == TLSProxy::Message::MT_SERVER_HELLO;
+ $psk_ext_in_sh = 1
+ if defined ${$message->extension_data}{TLSProxy::Message::EXT_PSK};
+ }
+}