Skip to content

Add support for EPA#682

Closed
paraddise wants to merge 6 commits into
FreeTDS:masterfrom
paraddise:master
Closed

Add support for EPA#682
paraddise wants to merge 6 commits into
FreeTDS:masterfrom
paraddise:master

Conversation

@paraddise
Copy link
Copy Markdown
Contributor

@paraddise paraddise commented Nov 1, 2025

#679
Implement for NTLM:

  • OpenSSL
  • GnuTLS
  • tests

Implement for Kerberos:

  • OpenSSL
  • GnuTLS

Implement for SSPI

  • OpenSSL
  • GnuTLS

Analyze the changes needed for TDS 8.0

@paraddise paraddise changed the title Draft: Add support for EPA Add support for EPA Nov 6, 2025
@paraddise
Copy link
Copy Markdown
Contributor Author

@mmcnabb-vms Can you look at this? Will this be merged at all or am I trying in vain?
If Yes, write please the plan what I need to add else to this PR. tests? implementation for other ssl library?

@freddy77
Copy link
Copy Markdown
Contributor

freddy77 commented Nov 6, 2025

Yes, surely a good feature to have. There's no rush I think, I saw the PR but the initial state was a bit messy so I waited.
It would be nice to have support for GnuTLS and SSPI too and a test but note I think is strictly necessary. But surely I would be nice to have at least a manual test.

@mmcnabb-vms
Copy link
Copy Markdown
Contributor

@mmcnabb-vms Can you look at this?

freddy is the maintainer, I'm just a random contributor :) working on other issues at the moment

@paraddise
Copy link
Copy Markdown
Contributor Author

paraddise commented Nov 19, 2025

@freddy77 Can you help me build freetds for windows? I've never done it before and I could not build it with Visual Studio Code 2022. Maybe there is a documentation how to configure viausl studio code 2022?
I'm getting error like in ci in AppVeyor

[ 10%] Built target tdsutils
[ 10%] Building C object src/utils/unittests/CMakeFiles/tds_test_base.dir/test_base.c.obj
test_base.c
[ 10%] Linking C static library tds_test_base.lib
[ 10%] Built target tds_test_base

NMAKE : fatal error U1073: don't know how to make 'C:\Users\Administrator\source\repos\freetds\src\replacements\iconv_charsets.h'

Stop.

NMAKE : fatal error U1077: '"C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\bin\HostX86\x86\nmake.exe" -s -f src\replacements\CMakeFiles\iconv_charsets_h.dir\build.make /nologo -SL                 src\replacements\CMakeFiles\iconv_charsets_h.dir\build' : return code '0x2'

Stop.

NMAKE : fatal error U1077: '"C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\bin\HostX86\x86\nmake.exe" -s -f CMakeFiles\Makefile2 /nologo -LS                 all' : return code '0x2'

Stop.

solved by install perl
But have another error

C:\Users\Administrator\source\repos\freetds\src\tds\tls.c(84): error C2037: left of 'init' specifies undefined struct/union 'bio_st'
C:\Users\Administrator\source\repos\freetds\src\tds\tls.c(90): error C2037: left of 'ptr' specifies undefined struct/union 'bio_st'
C:\Users\Administrator\source\repos\freetds\src\tds\tls.c(94): warning C4028: formal parameter 1 different from declaration
C:\Users\Administrator\source\repos\freetds\src\tds\tls.c(96): error C2037: left of 'ptr' specifies undefined struct/union 'bio_st'
SL                 src\tds\CMakeFiles\tds.dir\build' : return code '0x2'
Stop.
NMAKE : fatal error U1077: '"C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\bin\HostX86\x86\nmake.exe" -s -f CMakeFiles\Makefile2 /nologo -S                  all' : return code '0x2'
Stop.

@freddy77
Copy link
Copy Markdown
Contributor

freddy77 commented Nov 19, 2025

Good you fixed the Perl issue.
Building from git requires some more settings, from package some files are already generated to reduce dependencies.
One other option would have been to copy these files from a recent package.

About the error from tls.c it looks like BIO_get_data was not detected, it should be available. See include/config.h, try to define HAVE_BIO_GET_DATA.
From Appveyor, for instance, you have something like

-- Found OpenSSL: optimized;C:/OpenSSL-v35-Win64/lib/VC/x64/MD/libcrypto.lib;debug;C:/OpenSSL-v35-Win64/lib/VC/x64/MDd/libcrypto.lib (found version "3.5.4")
-- Looking for BIO_get_data
-- Looking for BIO_get_data - found
-- Looking for RSA_get0_key
-- Looking for RSA_get0_key - found
-- Looking for ASN1_STRING_get0_data
-- Looking for ASN1_STRING_get0_data - found
-- Looking for SSL_set_alpn_protos
-- Looking for SSL_set_alpn_protos - found

@paraddise
Copy link
Copy Markdown
Contributor Author

If I build with in Visual Studio Code with the folowing CMakeSettings.json

{
  "configurations": [
    {
      "name": "x64-Debug",
      "generator": "NMake Makefiles",
      "configurationType": "Debug",
      "inheritEnvironments": [ "msvc_x64_x64" ],
      "buildRoot": "${projectDir}\\build\\",
      "installRoot": "${projectDir}\\out\\install\\${name}",
      "cmakeCommandArgs": "",
      "ctestCommandArgs": "",
      "variables": [
        {
          "name": "ENABLE_EXTRA_CHECKS",
          "value": "false",
          "type": "BOOL"
        },
        {
          "name": "GPERF",
          "value": "C:/ProgramData/chocolatey/bin/gperf.exe",
          "type": "FILEPATH"
        },
        {
          "name": "LIB_EAY_DEBUG",
          "value": "C:/Program Files/OpenSSL-Win64/lib/VC/x64/MDd/libcrypto.lib",
          "type": "FILEPATH"
        },
        {
          "name": "LIB_EAY_RELEASE",
          "value": "C:/Program Files/OpenSSL-Win64/lib/VC/x64/MD/libcrypto.lib",
          "type": "FILEPATH"
        },
        {
          "name": "OPENSSL_APPLINK_SOURCE",
          "value": "C:/Program Files/OpenSSL-Win64/include/openssl/applink.c",
          "type": "FILEPATH"
        },
        {
          "name": "SSL_EAY_DEBUG",
          "value": "C:/Program Files/OpenSSL-Win64/lib/VC/x64/MDd/libssl.lib",
          "type": "FILEPATH"
        },
        {
          "name": "SSL_EAY_RELEASE",
          "value": "C:/Program Files/OpenSSL-Win64/lib/VC/x64/MD/libssl.lib",
          "type": "FILEPATH"
        },
        {
          "name": "WITH_OPENSSL",
          "value": "True",
          "type": "BOOL"
        },
        {
          "name": "ENABLE_MSDBLIB",
          "value": "True",
          "type": "BOOL"
        },
        {
          "name": "ENABLE_KRB5",
          "value": "True",
          "type": "BOOL"
        },
        {
          "name": "CMAKE_C_COMPILER",
          "value": "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.44.35207/bin/Hostx64/x64/cl.exe",
          "type": "FILEPATH"
        },
        {
          "name": "CMAKE_CXX_COMPILER",
          "value": "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.44.35207/bin/Hostx64/x64/cl.exe",
          "type": "FILEPATH"
        }
      ]
    },
    {
      "name": "x64-Debug-2",
      "generator": "Ninja",
      "configurationType": "Debug",
      "buildRoot": "${projectDir}\\out\\build\\${name}",
      "installRoot": "${projectDir}\\out\\install\\${name}",
      "cmakeCommandArgs": "",
      "buildCommandArgs": "",
      "ctestCommandArgs": "",
      "inheritEnvironments": [ "msvc_x64_x64" ],
      "variables": []
    }
  ]
}

Then it finds BIO_get_data
But after that it could not compile

[ 21%] Linking C executable strings.exe
LINK Pass 1: command "C:\PROGRA~1\MICROS~3\2022\COMMUN~1\VC\Tools\MSVC\1444~1.352\bin\Hostx64\x64\link.exe /nologo @CMakeFiles\r_strings.dir\objects1.rsp /out:strings.exe /implib:strings.lib /pdb:C:\Users\Administrator\source\repos\freetds\build\src\replacements\unittests\strings.pdb /version:0.0 /machine:x64 /debug /INCREMENTAL /subsystem:console ..\..\utils\unittests\tds_test_base.lib ..\replacements.lib ..\..\utils\tdsutils.lib C:\Users\Administrator\source\repos\freetds\iconv\lib\iconv.lib kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib /MANIFEST /MANIFESTFILE:CMakeFiles\r_strings.dir/intermediate.manifest CMakeFiles\r_strings.dir/manifest.res" failed (exit code 1120) with the following output:
strings.c.obj : error LNK2019: unresolved external symbol __imp_free referenced in function test_main
strings.c.obj : error LNK2019: unresolved external symbol __imp_malloc referenced in function test_main
strings.c.obj : error LNK2019: unresolved external symbol __imp__wassert referenced in function test_main
strings.c.obj : error LNK2019: unresolved external symbol memset referenced in function test_main
strings.c.obj : error LNK2019: unresolved external symbol strcmp referenced in function test_main
strings.c.obj : error LNK2019: unresolved external symbol strcpy referenced in function test_main
strings.c.obj : error LNK2001: unresolved external symbol _RTC_InitBase
replacements.lib(strlcpy.c.obj) : error LNK2001: unresolved external symbol _RTC_InitBase
replacements.lib(strlcat.c.obj) : error LNK2001: unresolved external symbol _RTC_InitBase
strings.c.obj : error LNK2001: unresolved external symbol _RTC_Shutdown
replacements.lib(strlcpy.c.obj) : error LNK2001: unresolved external symbol _RTC_Shutdown
replacements.lib(strlcat.c.obj) : error LNK2001: unresolved external symbol _RTC_Shutdown
LINK : error LNK2001: unresolved external symbol mainCRTStartup
replacements.lib(strlcpy.c.obj) : error LNK2019: unresolved external symbol memcpy referenced in function tds_strlcpy
replacements.lib(strlcat.c.obj) : error LNK2001: unresolved external symbol memcpy
replacements.lib(strlcpy.c.obj) : error LNK2019: unresolved external symbol strlen referenced in function tds_strlcpy
replacements.lib(strlcat.c.obj) : error LNK2001: unresolved external symbol strlen
C:\Users\Administrator\source\repos\freetds\iconv\lib\iconv.lib : warning LNK4272: library machine type 'x86' conflicts with target machine type 'x64'
C:\Program Files (x86)\Windows Kits\10\\lib\10.0.26100.0\\um\x86\kernel32.lib : warning LNK4272: library machine type 'x86' conflicts with target machine type 'x64'
C:\Program Files (x86)\Windows Kits\10\\lib\10.0.26100.0\\um\x86\user32.lib : warning LNK4272: library machine type 'x86' conflicts with target machine type 'x64'
C:\Program Files (x86)\Windows Kits\10\\lib\10.0.26100.0\\um\x86\gdi32.lib : warning LNK4272: library machine type 'x86' conflicts with target machine type 'x64'
C:\Program Files (x86)\Windows Kits\10\\lib\10.0.26100.0\\um\x86\winspool.lib : warning LNK4272: library machine type 'x86' conflicts with target machine type 'x64'
C:\Program Files (x86)\Windows Kits\10\\lib\10.0.26100.0\\um\x86\shell32.lib : warning LNK4272: library machine type 'x86' conflicts with target machine type 'x64'
C:\Program Files (x86)\Windows Kits\10\\lib\10.0.26100.0\\um\x86\ole32.lib : warning LNK4272: library machine type 'x86' conflicts with target machine type 'x64'
C:\Program Files (x86)\Windows Kits\10\\lib\10.0.26100.0\\um\x86\oleaut32.lib : warning LNK4272: library machine type 'x86' conflicts with target machine type 'x64'
C:\Program Files (x86)\Windows Kits\10\\lib\10.0.26100.0\\um\x86\uuid.lib : warning LNK4272: library machine type 'x86' conflicts with target machine type 'x64'
C:\Program Files (x86)\Windows Kits\10\\lib\10.0.26100.0\\um\x86\comdlg32.lib : warning LNK4272: library machine type 'x86' conflicts with target machine type 'x64'
C:\Program Files (x86)\Windows Kits\10\\lib\10.0.26100.0\\um\x86\advapi32.lib : warning LNK4272: library machine type 'x86' conflicts with target machine type 'x64'
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\lib\x86\MSVCRTD.lib : warning LNK4272: library machine type 'x86' conflicts with target machine type 'x64'

I don't understand why it uses x86 compiler, I don't know how to specity else if I specified via CMAKE_C_COMPILER

@freddy77
Copy link
Copy Markdown
Contributor

freddy77 commented Nov 19, 2025

It looks like your environment is compiling for x64 but trying to link to x86. I would try to use msvc_x64 instead of msvc_x64_x64.

Maybe you launched the wrong environment by mistake (if using command line) ?

Also Windows should use SSPI so ENABLE_KRB5 should be False.

@paraddise
Copy link
Copy Markdown
Contributor Author

Thank you. I managed to compile on Windows. I didn't notice the misc/run_with_compiler.cmd for a long time, but after I used it the project was built.
I added support for SSPI.
Tested with python script and pyodbc

import pyodbc
import os

conn = (
    "DRIVER=FreeTDSCustom;"
    "SERVER=127.0.0.1;"
    "Database=msdb;"
    "Port=1433;"
    "Trusted_Connection=yes;"
)

print("localhost version: ", pyodbc.connect(conn).execute("SELECT @@VERSION").fetchone())

@paraddise
Copy link
Copy Markdown
Contributor Author

If you have any questions about how to test, how to troubleshoot the connection, or how to configure the SQL Server or enable the EPA, I will be happy to help.
Tested on 2019 and 2022 SQL Servers with the latest updates installed.

@freddy77
Copy link
Copy Markdown
Contributor

freddy77 commented Nov 23, 2025

Currently testing changes to src/tds/challenge.c (from Linux).

Work:

  • TDS 7.4, required encryption, GnuTLS;
  • TDS 7.4, required encryption, OpenSSL (minor code change in order to compile).

Do no work:

  • required encryption off. At the time code tries to get the channel binding there's no TLS objects;
  • TDS 8.0, probably requires tls-exporter instead of tls-unique.

I still need to setup an AD domain to test GSSAPI.


Update: GSSAPI works too (this also with required encryption off).


Other update (25th November)

It looks like the "required encryption" issue is bound to the current poor implementation of NTLM code which lacks MIC. It looks like that if "required encryption" is off the server does not require channel binding (NTLM login with empty channel binding is accepted if using SSPI).

I still need to test SSPI implementation (I tried without your changes and works with "required encryption" off).

@freddy77 freddy77 self-requested a review November 25, 2025 14:49
@paraddise
Copy link
Copy Markdown
Contributor Author

paraddise commented Nov 25, 2025

I can't get channel binding working for TLS 1.3. First, I wrote a golang implementation of the tls-exporter. The channel binding implementation was simple, but I didn't understand how Microsoft calculated it. Do you know which DLL or binary I could reverse to understand the secret?

I also want to point out that we need to test this on fresh MSSQL servers, as Microsoft Server 2019 does not support TLS 1.3 and when you use the encrypt=strict option, you will be using TLS 1.2 instead.
So it's better to test 2019 and 2022 on Winwdows Server 2019 and 2022

And very old mssql servers have channel binding checks broken, they ignore them even if you set Enhanced Protection = Required

@freddy77
Copy link
Copy Markdown
Contributor

I can't get channel binding working for TLS 1.3. First, I wrote a golang implementation of the tls-exporter. The channel binding implementation was simple, but I didn't understand how Microsoft calculated it. Do you know which DLL or binary I could reverse to understand the secret?

I suppose then your code it's not working. Looking around I would look at "token bindings" (rfc 8471) instead of tls exporter and rfc 9266. The DLL should be schannel.dll but please don't do it, I won't like to go to legal issues.

I also want to point out that we need to test this on fresh MSSQL servers, as Microsoft Server 2019 does not support TLS 1.3 and when you use the encrypt=strict option, you will be using TLS 1.2 instead. So it's better to test 2019 and 2022 on Winwdows Server 2019 and 2022

I'm getting TLS 1.3 on w2022, just adding some registry keys.

And very old mssql servers have channel binding checks broken, they ignore them even if you set Enhanced Protection = Required

I don't think we can do anything about it. Unless we suggest to just force encryption at the client level.

@paraddise
Copy link
Copy Markdown
Contributor Author

I don't see any tls extensions with token binding in Client Hello message.

@paraddise
Copy link
Copy Markdown
Contributor Author

Maybe we can skip this for tds 8.0 and tls 1.3?
I could not find the project that implemented it.
I think we can create issue and wait until microsoft will issue some documentation how to build channel building structure with tls 1.3 with InitializeSecurityContext.

@freddy77
Copy link
Copy Markdown
Contributor

Maybe we can skip this for tds 8.0 and tls 1.3? I could not find the project that implemented it. I think we can create issue and wait until microsoft will issue some documentation how to build channel building structure with tls 1.3 with InitializeSecurityContext.

Yes, already working on it, testing is part one.
Looking at the way you did the commit I suppose I can pretty much merge them.
I can came out with commit message, or you can suggest.
I'll try to prepare and send what I'll get when I finish.

About TLS 1.3 is even possible that simply they "trust it", in the sense that with strict mode the certificate is required and all encrypted too so you can't have much man in the middle.

@freddy77
Copy link
Copy Markdown
Contributor

The proposed version is at https://github.com/freddy77/freetds/commits/epa/.

Changes I did:

  • reduced differences removing indentation changes;
  • move common code to src/tds/tls.c and include/freetds/tls.h;
  • removed some allocations and leaks;
  • do not mix declaration and code, some compiler does not like this;
  • send channel binding on NTLM even if encryption is not set to force or strict;
  • fixed minor compiler issues;
  • add license and description to test;
  • better check for target info from server.

You can see the full changes at https://github.com/freddy77/freetds/commits/epa0/ (before reorganizing the series).
The commit have your name, I retained the ****.qemu email. Is that correct?
Commit freddy77@a78149e has most information, more or less taken from your issue report and rephrased.

@paraddise
Copy link
Copy Markdown
Contributor Author

You can see the full changes at https://github.com/freddy77/freetds/commits/epa0/ (before reorganizing the series).

Oh, I really appreciate it that you refactored, I'm not great at C and there were memory leaks left, thank you!

The commit have your name, I retained the ****.qemu email. Is that correct?

You are right, .qemu email is wrong, it should be the same as in other commits. And I forgot to change git name in commits and need to change B** G** to my github username.
Can I do it? or you will?

About TLS 1.3 is even possible that simply they "trust it", in the sense that with strict mode the certificate is required and all encrypted too so you can't have much man in the middle.

I'll try to not send CB when using tls 1.3, maybe it will help.

I can came out with commit message, or you can suggest.

I think you have a better understanding how to name commit, but I'd name this commit "Add support of Channel Binding for TLS up to 1.2"

@freddy77
Copy link
Copy Markdown
Contributor

You can see the full changes at https://github.com/freddy77/freetds/commits/epa0/ (before reorganizing the series).

Oh, I really appreciate it that you refactored, I'm not great at C and there were memory leaks left, thank you!

The commit have your name, I retained the ****.qemu email. Is that correct?

You are right, .qemu email is wrong, it should be the same as in other commits. And I forgot to change git name in commits and need to change B** G** to my github username. Can I do it? or you will?

For the email address no issue. The name no, I need a real name.

@freddy77
Copy link
Copy Markdown
Contributor

Merged. Thanks

@freddy77 freddy77 closed this Nov 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants