Get-DbaNetworkEncryption - Add command to retrieve TLS certificate from SQL Server network#10255
Get-DbaNetworkEncryption - Add command to retrieve TLS certificate from SQL Server network#10255andreasjordan wants to merge 5 commits intodevelopmentfrom
Conversation
…e from SQL Server network Adds Get-DbaNetworkEncryption which retrieves the TLS/SSL certificate presented by a SQL Server instance during the TLS handshake, without requiring Windows host access or WinRM. Fixes #9112 Key features: - Connects directly to SQL Server's TCP port via TLS/SSL - No Windows host access required (no WinRM) - Handles named instances via SQL Browser (UDP 1434) with proper DNS resolution - Returns Subject, Issuer, Thumbprint, Expiration, DNS SANs, and more - Graceful error handling for instances without TLS configured - Tests skip cleanly when no certificate is configured (do Get-DbaNetworkEncryption) Co-authored-by: Andreas Jordan <andreasjordan@users.noreply.github.com>
|
very cool command! |
|
@claude The command does not work. This is the verbose output: The variable |
|
Claude finished @andreasjordan's task in 3m 57s —— View job Fixed: Malformed Pre-Login Packet
Root cause: The The original packet had 5 option entries (VERSION, ENCRYPTION, INSTOPT, THREADID, MARS) × 5 bytes each + 1 terminator = 26 bytes of headers, meaning data could only start at payload offset 26 or higher. But the offsets claimed:
SQL Server detected the malformed packet and closed the TCP connection immediately, causing Fix: Simplified to just two options (VERSION + ENCRYPTION) with correct offsets:
Total packet: 8 (TDS header) + 18 (payload) = 26 bytes = 0x1A — matches the length field. Commit: |
…esRead=0 The pre-login byte array had incorrect data-section offsets. With 5 option headers (5 bytes each) plus a terminator, the headers occupy payload bytes 0-25, so data must start at offset 26 or higher. The original offsets (21-29) caused VERSION data to overlap with the MARS header and terminator bytes, producing a malformed TDS pre-login packet that SQL Server rejected by closing the connection, resulting in NetworkStream.Read() returning 0. Fixed by simplifying to two options (VERSION + ENCRYPTION) with correct offsets: VERSION data at payload offset 11, ENCRYPTION data at offset 17, total packet 26 bytes. (do Get-DbaNetworkEncryption) Co-authored-by: Andreas Jordan <andreasjordan@users.noreply.github.com>
|
@claude Now I get this error: |
|
Claude finished @andreasjordan's task in 3m 54s —— View job Fixed: TLS Handshake Timeout
Root cause: SQL Server uses a STARTTLS-style TLS negotiation where TLS handshake messages (ClientHello, ServerHello, etc.) are wrapped inside TDS packets (type Fix in commit Added
Bonus fix: The server's pre-login response is now parsed to find the
The |
SQL Server uses STARTTLS-style TLS negotiation where TLS ClientHello/ServerHello messages are wrapped inside TDS packets (type 0x12) during the handshake phase. Previously we were sending a raw TLS ClientHello directly to the NetworkStream, causing SQL Server to wait for a valid TDS packet and the AuthenticateAsClient call to time out. Fix: Add DbaTools.TdsWrappingStream (a custom Stream subclass compiled via Add-Type) that transparently adds TDS packet framing on writes and strips it on reads. The SslStream now wraps this TdsWrappingStream instead of the raw NetworkStream. Also added: parsing of the ENCRYPTION field in the server's pre-login response to emit a clear error when the server has TLS disabled (ENCRYPT_NOT_SUP = 0x02). (do Get-DbaNetworkEncryption) Co-authored-by: Andreas Jordan <andreasjordan@users.noreply.github.com>
|
@claude Now the command does not fail anymore, but returns an empty output: But the instance has a certificate configured. |
|
Claude finished @andreasjordan's task in 1m 11s —— View job Fixed: Empty Certificate Properties
Root cause: The Fix (commit |
…SslStream.RemoteCertificate Replace callback-based certificate capture ($script:capturedCertificate) with $sslStream.RemoteCertificate. Scriptblock callbacks invoked by .NET do not reliably write back to PowerShell session variables, so the captured variable stayed null and New-Object X509Certificate2($null) produced an empty object. Reading RemoteCertificate directly after AuthenticateAsClient is the correct approach. (do Get-DbaNetworkEncryption) Co-authored-by: Andreas Jordan <andreasjordan@users.noreply.github.com>
|
Ok, the command works now as expected. But the code is from Claude and not (as in the issue suggested) based on the function from Jordan Borean (https://gist.github.com/jborean93/44f92e4dfa613c5a1e7889fa7a7c2563). I locally changed the code to use the function from Jordan Borean and it worked as well. So now I'm not sure where we want to go. And I don't want to decide. What do you think, @potatoqualitee ? |
Fixes #9112
Adds
Get-DbaNetworkEncryptionwhich retrieves the TLS/SSL certificate presented by a SQL Server instance during the TLS handshake, without requiring Windows host access or WinRM.Key features:
This complements
Get-DbaNetworkCertificate(which reads from the Windows registry, requires WinRM) by instead showing what certificate is actually being presented to clients.Generated with Claude Code