| File: System\Net\Quic\Internal\MsQuicTlsSecret.cs | Web Access |
| Project: src\runtime\src\libraries\System.Net.Quic\src\System.Net.Quic.csproj (System.Net.Quic) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using System.Text; using Microsoft.Quic; using static Microsoft.Quic.MsQuic; namespace System.Net.Quic; internal sealed class MsQuicTlsSecret : IDisposable { private unsafe QUIC_TLS_SECRETS* _tlsSecrets; public static unsafe MsQuicTlsSecret? Create(MsQuicContextSafeHandle handle) { if (!SslKeyLogger.IsEnabled) { return null; } QUIC_TLS_SECRETS* tlsSecrets = null; try { tlsSecrets = (QUIC_TLS_SECRETS*)NativeMemory.AllocZeroed((nuint)sizeof(QUIC_TLS_SECRETS)); MsQuicHelpers.SetMsQuicParameter(handle, QUIC_PARAM_CONN_TLS_SECRETS, (uint)sizeof(QUIC_TLS_SECRETS), (byte*)tlsSecrets); MsQuicTlsSecret instance = new MsQuicTlsSecret(tlsSecrets); handle.Disposable = instance; return instance; } catch (Exception ex) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Error(handle, $"Failed to set native memory for TLS secret: {ex}"); } if (tlsSecrets is not null) { NativeMemory.Free(tlsSecrets); } return null; } } private unsafe MsQuicTlsSecret(QUIC_TLS_SECRETS* tlsSecrets) { _tlsSecrets = tlsSecrets; } public unsafe void WriteSecret() { ReadOnlySpan<byte> clientRandom = _tlsSecrets->IsSet.ClientRandom != 0 ? new ReadOnlySpan<byte>(_tlsSecrets->ClientRandom, 32) : ReadOnlySpan<byte>.Empty; Span<byte> clientHandshakeTrafficSecret = _tlsSecrets->IsSet.ClientHandshakeTrafficSecret != 0 ? new Span<byte>(_tlsSecrets->ClientHandshakeTrafficSecret, _tlsSecrets->SecretLength) : Span<byte>.Empty; Span<byte> serverHandshakeTrafficSecret = _tlsSecrets->IsSet.ServerHandshakeTrafficSecret != 0 ? new Span<byte>(_tlsSecrets->ServerHandshakeTrafficSecret, _tlsSecrets->SecretLength) : Span<byte>.Empty; Span<byte> clientTrafficSecret0 = _tlsSecrets->IsSet.ClientTrafficSecret0 != 0 ? new Span<byte>(_tlsSecrets->ClientTrafficSecret0, _tlsSecrets->SecretLength) : Span<byte>.Empty; Span<byte> serverTrafficSecret0 = _tlsSecrets->IsSet.ServerTrafficSecret0 != 0 ? new Span<byte>(_tlsSecrets->ServerTrafficSecret0, _tlsSecrets->SecretLength) : Span<byte>.Empty; Span<byte> clientEarlyTrafficSecret = _tlsSecrets->IsSet.ClientEarlyTrafficSecret != 0 ? new Span<byte>(_tlsSecrets->ClientEarlyTrafficSecret, _tlsSecrets->SecretLength) : Span<byte>.Empty; SslKeyLogger.WriteSecrets( clientRandom, clientHandshakeTrafficSecret, serverHandshakeTrafficSecret, clientTrafficSecret0, serverTrafficSecret0, clientEarlyTrafficSecret); // clear secrets already logged, so they are not logged again on next call, // keep ClientRandom as it is used for all secrets (and is not a secret itself) if (!clientHandshakeTrafficSecret.IsEmpty) { clientHandshakeTrafficSecret.Clear(); _tlsSecrets->IsSet.ClientHandshakeTrafficSecret = 0; } if (!serverHandshakeTrafficSecret.IsEmpty) { serverHandshakeTrafficSecret.Clear(); _tlsSecrets->IsSet.ServerHandshakeTrafficSecret = 0; } if (!clientTrafficSecret0.IsEmpty) { clientTrafficSecret0.Clear(); _tlsSecrets->IsSet.ClientTrafficSecret0 = 0; } if (!serverTrafficSecret0.IsEmpty) { serverTrafficSecret0.Clear(); _tlsSecrets->IsSet.ServerTrafficSecret0 = 0; } if (!clientEarlyTrafficSecret.IsEmpty) { clientEarlyTrafficSecret.Clear(); _tlsSecrets->IsSet.ClientEarlyTrafficSecret = 0; } } public unsafe void Dispose() { if (_tlsSecrets is null) { return; } lock (this) { if (_tlsSecrets is null) { return; } QUIC_TLS_SECRETS* tlsSecrets = _tlsSecrets; _tlsSecrets = null; NativeMemory.Free(tlsSecrets); } } }