Skip to content

fix: add actionable guidance for TLS handshake failures in Go 1.23+/1.25+#356

Open
dlevy-msft-sql wants to merge 7 commits into
microsoft:mainfrom
dlevy-msft-sql:fix/tls-handshake-error-guidance
Open

fix: add actionable guidance for TLS handshake failures in Go 1.23+/1.25+#356
dlevy-msft-sql wants to merge 7 commits into
microsoft:mainfrom
dlevy-msft-sql:fix/tls-handshake-error-guidance

Conversation

@dlevy-msft-sql

Copy link
Copy Markdown

Summary

Wraps TLS handshake errors with specific GODEBUG workaround instructions when Go's crypto/tls rejects server certificates due to policy changes in newer Go versions.

Problem

Users hitting TLS handshake failures get opaque error messages with no guidance on how to resolve them:

Changes

  • Add wrapTLSError() helper in tds.go that pattern-matches known TLS error strings and appends actionable workaround text (specific GODEBUG environment variable settings)
  • Apply at both TLS handshake sites: getTLSConn() (strict/TDS8 path) and connect() (standard encryption path)
  • Fix the standard encryption path to use %w instead of %v for proper error wrapping
  • Add unit tests for all error patterns

What this does NOT do

  • Does not bypass Go's TLS security defaults
  • Does not add SHA-1 support to the driver
  • Does not change any connection behavior

Example error messages

Before:

TLS Handshake failed: tls: peer certificate uses SHA-1 based signature

After:

TLS Handshake failed: tls: peer certificate uses SHA-1 based signature. The server uses SHA-1 signatures, which Go 1.25+ disallows per RFC 9155. Set GODEBUG=tlssha1=1 to allow it, update the server certificate to SHA-256+, or use encrypt=disable for non-production servers

Closes #302, closes #217, closes #231

@codecov-commenter

codecov-commenter commented Apr 17, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.62%. Comparing base (c10fa99) to head (81125d5).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##             main     #356       +/-   ##
===========================================
+ Coverage   80.66%   96.62%   +15.95%     
===========================================
  Files          35       92       +57     
  Lines        6842    74379    +67537     
===========================================
+ Hits         5519    71865    +66346     
- Misses       1055     2177     +1122     
- Partials      268      337       +69     
Flag Coverage Δ
unittests 96.55% <100.00%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
tds.go 71.32% <100.00%> (+1.63%) ⬆️

... and 59 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@dlevy-msft-sql dlevy-msft-sql added this to the v1.11.0 milestone Apr 17, 2026
@dlevy-msft-sql dlevy-msft-sql force-pushed the fix/tls-handshake-error-guidance branch 2 times, most recently from 15dc192 to 1785b05 Compare April 24, 2026 21:10
….25+

Wraps TLS handshake errors with GODEBUG hints when Go rejects SHA-1
certificates or negative serial numbers. Uses case-insensitive matching
for SHA-1 error detection across Go versions.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Improves the driver’s TLS handshake failure diagnostics by wrapping handshake errors with actionable guidance (including relevant GODEBUG workarounds) for known Go crypto/tls policy changes, helping users self-remediate certificate-related failures.

Changes:

  • Add wrapTLSError() in tds.go to recognize specific TLS/cert failure strings and append remediation guidance.
  • Apply the wrapper at both TLS handshake sites (getTLSConn() and the standard encryption path in connect()), ensuring proper error wrapping (%w).
  • Add unit tests covering the known patterns and default behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
tds.go Introduces wrapTLSError() and uses it at both TLS handshake call sites to enrich errors with guidance.
tds_unit_test.go Adds unit tests validating wrapping behavior, message contents, and errors.Is unwrapping.

Comment thread tds.go Outdated
Comment thread tds.go Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

Comment thread tds_unit_test.go Outdated
Comment thread tds_unit_test.go
Comment thread tds.go
Comment thread tds_unit_test.go
Comment thread tds_unit_test.go Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment thread tds.go Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@dlevy-msft-sql dlevy-msft-sql requested a review from Copilot April 27, 2026 17:00

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

Comment thread tds.go
Comment thread tds.go Outdated
Comment thread tds_unit_test.go Outdated
Comment thread tds_unit_test.go Outdated
Comment thread tds_unit_test.go Outdated
- Change wrapTLSError to require both 'cannot read handshake' AND 'eof'
  instead of matching either independently. Prevents false SHA-1 guidance
  for unrelated network errors.
- Add server-side conn.SetDeadline in TestConnectNonStrictTLSHandshakeError
  to prevent goroutine hangs.
- Reduce TestGetTLSConnHandshakeError timeout from 5s to 1s.
- Replace raw DSN string with net/url builder for proper parameter encoding.
- Add test case verifying handshake-without-EOF falls to default wrapper.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

silverwind pushed a commit to go-gitea/gitea that referenced this pull request May 27, 2026
The following TLS handshake error is fixed by newer versions of mssql
(refer to
microsoft/mssql-docker#895 (comment))

```
TLS Handshake failed: tls: failed to parse certificate from server: x509: negative serial number
```

Based on
microsoft/go-sqlcmd#755 (comment),
newer versions of mssql don't have this problem. And there're changes
going to mssql driver side to make this error more explicit
microsoft/go-mssqldb#356.

---------

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants