Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions tls-uses-pqc/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

// Create a self-signed certificate.
using var key = ECDsa.Create();
Comment thread
tmds marked this conversation as resolved.
var certReq = new CertificateRequest("CN=localhost", key, HashAlgorithmName.SHA256);
using var cert = certReq.CreateSelfSigned(DateTimeOffset.UtcNow.AddMinutes(-1), DateTimeOffset.UtcNow.AddYears(1));

// Set up a loopback TCP connection.
var listener = new TcpListener(IPAddress.Loopback, 0);
listener.Start();
int port = ((IPEndPoint)listener.LocalEndpoint).Port;

// Server side: accept and authenticate as TLS server.
var serverTask = Task.Run(async () =>
{
using var serverClient = await listener.AcceptTcpClientAsync();
await using var serverSsl = new SslStream(serverClient.GetStream(), false);
await serverSsl.AuthenticateAsServerAsync(cert);
return GetNegotiatedGroupName(serverSsl);
});

// Client side: connect and authenticate as TLS client.
using var client = new TcpClient();
await client.ConnectAsync(IPAddress.Loopback, port);
await using var clientSsl = new SslStream(client.GetStream(), false, (sender, certificate, chain, errors) => true /* accept cert */);
await clientSsl.AuthenticateAsClientAsync("localhost");

string? clientGroup = GetNegotiatedGroupName(clientSsl);
string? serverGroup = await serverTask;
listener.Stop();

Console.WriteLine($"Client negotiated group: {clientGroup}");
Console.WriteLine($"Server negotiated group: {serverGroup}");

// Verify PQC was used: the group name should contain "MLKEM".
bool clientPqc = clientGroup != null && clientGroup.Contains("MLKEM", StringComparison.OrdinalIgnoreCase);
bool serverPqc = serverGroup != null && serverGroup.Contains("MLKEM", StringComparison.OrdinalIgnoreCase);

if (clientPqc && serverPqc)
{
Console.WriteLine("PASS: PQC key exchange negotiated.");
return 0;
}

Console.WriteLine($"FAIL: Expected PQC key exchange group containing 'MLKEM', got client: '{clientGroup}', server: '{serverGroup}'");
return 1;

// Use OpenSSL interop to get the negotiated key exchange group (SslStream doesn't expose this information).
static string? GetNegotiatedGroupName(SslStream sslStream)
{
var secCtxField = typeof(SslStream).GetField("_securityContext", BindingFlags.NonPublic | BindingFlags.Instance)!;
var safeSslHandle = (SafeHandle)secCtxField.GetValue(sslStream)!;
bool added = false;
safeSslHandle.DangerousAddRef(ref added);
try
{
IntPtr namePtr = SSL_get0_group_name(safeSslHandle.DangerousGetHandle());
return namePtr == IntPtr.Zero ? null : Marshal.PtrToStringAnsi(namePtr);
}
finally
{
if (added) safeSslHandle.DangerousRelease();
}
}

[DllImport("libssl.so.3")]
static extern IntPtr SSL_get0_group_name(IntPtr ssl);
16 changes: 16 additions & 0 deletions tls-uses-pqc/test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "tls-uses-pqc",
"enabled": true,
"requiresSdk": true,
"version": "10.0",
"versionSpecific": false,
"type": "bash",
"cleanup": true,
"ignoredRIDs":[
"rhel.8", // no PQC key exchange support
"rhel.9", // no PQC key exchange support
"centos.8", // no PQC key exchange support
"centos.9", // no PQC key exchange support
"fedora.42" // no PQC key exchange support
]
}
6 changes: 6 additions & 0 deletions tls-uses-pqc/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env bash

set -euo pipefail
IFS=$'\n\t'

dotnet run
10 changes: 10 additions & 0 deletions tls-uses-pqc/tls-uses-pqc.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>$(TestTargetFramework)</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

</Project>
Loading