Skip to content

Commit d95ab31

Browse files
authored
Addressed CVE-2025-59250 and version updates for 13.2.1 (#2801)
* Addressed CVE-2025-59250: JDBC Driver for SQL Server Spoofing Vulnerability: Improper input validation in JDBC Driver for SQL Server allows an unauthorized attacker to perform spoofing over a network.
1 parent 531bbd2 commit d95ab31

File tree

17 files changed

+263
-65
lines changed

17 files changed

+263
-65
lines changed

CHANGELOG.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,60 @@
22
All notable changes to this project will be documented in this file.
33

44
The format is based on [Keep a Changelog](http://keepachangelog.com/)
5+
## [13.2.1] Hotfix & Stable Release
6+
7+
### Added
8+
9+
- **Enable Vector data type tests on Azure SQL Database** [#2762](https://github.com/microsoft/mssql-jdbc/pull/2762)
10+
**What was added**: Vector data type tests are now enabled to run against Azure SQL Database.
11+
**Who benefits**: Developers testing VECTOR functionality in Azure SQL DB environments.
12+
**Impact**: Ensures VECTOR data type support test coverage.
13+
14+
- **Enable JSON data type tests on Azure SQL Database** [#2756](https://github.com/microsoft/mssql-jdbc/pull/2756)
15+
**What was added**: JSON data type tests are now enabled to run against Azure SQL Database.
16+
**Who benefits**: Developers testing JSON functionality in Azure SQL DB environments.
17+
**Impact**: Ensures JSON data type support test coverage.
18+
19+
### Changed
20+
21+
- **Revert function/procedure filtering via sys.all_objects** [#2751](https://github.com/microsoft/mssql-jdbc/pull/2751)
22+
**What changed**: Reverted #2705 change that used sys.all_objects for filtering. Restores previous behavior to maintain consistency across metadata APIs.
23+
**Who benefits**: Developers using getProcedures() and getFunctions() in JDBC.
24+
**Impact**: Preserves compatibility with numbered procedures and avoids discrepancies between APIs.
25+
26+
### Fixed issues
27+
28+
- **JDK 8 compatibility for vector datatype handling** [#2750](https://github.com/microsoft/mssql-jdbc/pull/2750)
29+
**What was fixed**: Ensured fallback to JVM system property javax.net.ssl.trustStoreType if connection property is unset.
30+
**Who benefits**: Users configuring SSL via system properties.
31+
**Impact**: Enables proper SSL trust store resolution, improving compatibility with system configurations.
32+
33+
- **PreparedStatement getGeneratedKeys() failure with triggers** [#2742](https://github.com/microsoft/mssql-jdbc/pull/2742)
34+
**What was fixed**: Fixed error "The statement must be executed before any results can be obtained" when using insert triggers with generated keys.
35+
**Who benefits**: Developers retrieving generated keys from inserts with triggers.
36+
**Impact**: Restores correct behavior for both update count accuracy and generated keys retrieval in trigger scenarios.
37+
38+
- **Byte Buddy dependency scope** [#2755](https://github.com/microsoft/mssql-jdbc/pull/2755)
39+
**What was fixed**: Corrected Byte Buddy (1.15.11) dependency scope to test instead of compile.
40+
**Who benefits**: Developers and users of runtime artifacts.
41+
**Impact**: Reduces runtime artifact size (~8 MB) and ensures Byte Buddy is only included for unit tests.
42+
43+
- **DatabaseMetaData.getIndexInfo() NON_UNIQUE value inconsistency** [#2773](https://github.com/microsoft/mssql-jdbc/pull/2773)
44+
**What was fixed**: Fixed incorrect NON_UNIQUE values due to mismatched handling of sp_statistics and sys.indexes.
45+
**Who benefits**: Applications depending on accurate index metadata.
46+
**Impact**: Provides consistent value of NON_UNIQUE field across SQL Server and Azure Synapse Analytics.
47+
48+
- **DatabaseMetaData.getIndexInfo() invalid cursor position exception** [2763](https://github.com/microsoft/mssql-jdbc/pull/2763)
49+
**What was fixed**: Fixed SQLException: Invalid cursor position caused when calling ResultSet.next() after exhaustion due to CachedRowSet strict cursor validation.
50+
**Who benefits**: Developers consuming metadata via DatabaseMetaData.getIndexInfo() on SQL Server or Azure Synapse DW.
51+
**Impact**: Replaces CachedRowSet merging with a UNION ALL query, ensuring standard JDBC cursor behavior while maintaining columnstore index support.
52+
53+
- **Address a hostname validation vulnerability by securely parsing certificate common names.**
54+
**What was fixed**: Secure hostname validation is enforced by replacing the vulnerable CN parsing logic in SQLServerCertificateUtils.java, preventing spoofing attacks.
55+
**Who benefits**: All users of the SQL Server JDBC driver, especially those relying on TLS for secure connections, benefit from improved certificate validation.
56+
**Impact**: This fix closes a security gap, protecting applications from man-in-the-middle attacks and ensuring compliance with security best practices.
57+
58+
559
## [13.2.0] Stable Release
660

761
### Changed

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ We're now on the Maven Central Repository. Add the following to your POM file to
8383
<dependency>
8484
<groupId>com.microsoft.sqlserver</groupId>
8585
<artifactId>mssql-jdbc</artifactId>
86-
<version>13.2.0.jre11</version>
86+
<version>13.2.1.jre11</version>
8787
</dependency>
8888
```
8989
The driver can be downloaded from [Microsoft](https://aka.ms/downloadmssqljdbc). For driver version 12.1.0 and greater, please use the jre11 version when using Java 11 or greater, and the jre8 version when using Java 8.
@@ -94,7 +94,7 @@ To get the latest version of the driver, add the following to your POM file:
9494
<dependency>
9595
<groupId>com.microsoft.sqlserver</groupId>
9696
<artifactId>mssql-jdbc</artifactId>
97-
<version>13.2.0.jre11</version>
97+
<version>13.2.1.jre11</version>
9898
</dependency>
9999
```
100100

@@ -129,7 +129,7 @@ Projects that require either of the two features need to explicitly declare the
129129
<dependency>
130130
<groupId>com.microsoft.sqlserver</groupId>
131131
<artifactId>mssql-jdbc</artifactId>
132-
<version>13.2.0.jre11</version>
132+
<version>13.2.1.jre11</version>
133133
<scope>compile</scope>
134134
</dependency>
135135

@@ -147,7 +147,7 @@ Projects that require either of the two features need to explicitly declare the
147147
<dependency>
148148
<groupId>com.microsoft.sqlserver</groupId>
149149
<artifactId>mssql-jdbc</artifactId>
150-
<version>13.2.0.jre11</version>
150+
<version>13.2.1.jre11</version>
151151
<scope>compile</scope>
152152
</dependency>
153153

@@ -174,7 +174,7 @@ When setting 'useFmtOnly' property to 'true' for establishing a connection or cr
174174
<dependency>
175175
<groupId>com.microsoft.sqlserver</groupId>
176176
<artifactId>mssql-jdbc</artifactId>
177-
<version>13.2.0.jre11</version>
177+
<version>13.2.1.jre11</version>
178178
</dependency>
179179

180180
<dependency>

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
apply plugin: 'java'
1313

14-
version = '13.2.0'
14+
version = '13.2.1'
1515
def releaseExt = ''
1616
def jreVersion = ""
1717
def testOutputDir = file("build/classes/java/test")

mssql-jdbc_auth_LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
MICROSOFT SOFTWARE LICENSE TERMS
2-
MICROSOFT JDBC DRIVER 13.2.0 FOR SQL SERVER
2+
MICROSOFT JDBC DRIVER 13.2.1 FOR SQL SERVER
33

44
These license terms are an agreement between you and Microsoft Corporation (or one of its affiliates). They apply to the software named above and any Microsoft services or software updates (except to the extent such services or updates are accompanied by new or additional terms, in which case those different terms apply prospectively and do not alter your or Microsoft’s rights relating to pre-updated software or services). IF YOU COMPLY WITH THESE LICENSE TERMS, YOU HAVE THE RIGHTS BELOW. BY USING THE SOFTWARE, YOU ACCEPT THESE TERMS.
55

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<modelVersion>4.0.0</modelVersion>
66
<groupId>com.microsoft.sqlserver</groupId>
77
<artifactId>mssql-jdbc</artifactId>
8-
<version>13.2.0</version>
8+
<version>13.2.1</version>
99
<packaging>jar</packaging>
1010
<name>Microsoft JDBC Driver for SQL Server</name>
1111
<description>

src/main/java/com/microsoft/sqlserver/jdbc/SQLJdbcVersion.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
final class SQLJdbcVersion {
99
static final int MAJOR = 13;
1010
static final int MINOR = 2;
11-
static final int PATCH = 0;
11+
static final int PATCH = 1;
1212
static final int BUILD = 0;
1313
/*
1414
* Used to load mssql-jdbc_auth DLL.

src/main/java/com/microsoft/sqlserver/jdbc/SQLServerCertificateUtils.java

Lines changed: 46 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@
5050
import javax.crypto.spec.SecretKeySpec;
5151
import javax.net.ssl.KeyManager;
5252
import javax.net.ssl.KeyManagerFactory;
53+
import javax.naming.ldap.LdapName;
54+
import javax.naming.ldap.Rdn;
55+
import javax.security.auth.x500.X500Principal;
5356

5457
import org.bouncycastle.openssl.PEMDecryptorProvider;
5558
import org.bouncycastle.openssl.PEMEncryptedKeyPair;
@@ -77,45 +80,6 @@ static KeyManager[] getKeyManagerFromFile(String certPath, String keyPath,
7780
}
7881
}
7982

80-
/**
81-
* Parse name in RFC 2253 format Returns the common name if successful, null if failed to find the common name. The
82-
* parser tuned to be safe than sorry so if it sees something it can't parse correctly it returns null
83-
*
84-
* @param distinguishedName
85-
* server name to parse
86-
* @return subject name
87-
*/
88-
static String parseCommonName(String distinguishedName) {
89-
int index;
90-
// canonical name converts entire name to lowercase
91-
index = distinguishedName.indexOf("cn=");
92-
if (index == -1) {
93-
return null;
94-
}
95-
distinguishedName = distinguishedName.substring(index + 3);
96-
// Parse until a comma or end is reached
97-
// Note the parser will handle gracefully (essentially will return empty string) , inside the quotes (e.g
98-
// cn="Foo, bar") however
99-
// RFC 952 says that the hostName cant have commas however the parser should not (and will not) crash if it
100-
// sees a , within quotes.
101-
for (index = 0; index < distinguishedName.length(); index++) {
102-
if (distinguishedName.charAt(index) == ',') {
103-
break;
104-
}
105-
}
106-
String commonName = distinguishedName.substring(0, index);
107-
// strip any quotes
108-
if (commonName.length() > 1 && ('\"' == commonName.charAt(0))) {
109-
if ('\"' == commonName.charAt(commonName.length() - 1))
110-
commonName = commonName.substring(1, commonName.length() - 1);
111-
else {
112-
// Be safe the name is not ended in " return null so the common Name wont match
113-
commonName = null;
114-
}
115-
}
116-
return commonName;
117-
}
118-
11983
/**
12084
* Validate server name in certificate matches hostname
12185
*
@@ -183,7 +147,11 @@ static boolean validateServerName(String nameInCert, String hostName) {
183147
* @throws CertificateException
184148
*/
185149
static void validateServerNameInCertificate(X509Certificate cert, String hostName) throws CertificateException {
186-
String nameInCertDN = cert.getSubjectX500Principal().getName("canonical");
150+
// Use RFC2253 format and secure CN parsing to avoid ambiguities introduced by
151+
// the "canonical" format (which lowercases and reverses RDN order). We rely
152+
// on LdapName/Rdn to securely parse the DN and extract the CN attribute only.
153+
X500Principal subjectPrincipal = cert.getSubjectX500Principal();
154+
String nameInCertDN = subjectPrincipal.getName(X500Principal.RFC2253);
187155

188156
if (logger.isLoggable(Level.FINER)) {
189157
logger.finer(logContext + " Validating the server name:" + hostName);
@@ -194,7 +162,13 @@ static void validateServerNameInCertificate(X509Certificate cert, String hostNam
194162
String dnsNameInSANCert = "";
195163

196164
// the name in cert is in RFC2253 format parse it to get the actual subject name
197-
String subjectCN = parseCommonName(nameInCertDN);
165+
String subjectCN = parseCommonNameSecure(cert);
166+
// X.509 certificate standard requires domain names to be in ASCII.
167+
// Even IDN (Unicode) names will be represented here in Punycode (ASCII).
168+
// Normalize case for comparison using English to avoid case issues like Turkish i.
169+
if (subjectCN != null) {
170+
subjectCN = subjectCN.toLowerCase(Locale.ENGLISH);
171+
}
198172

199173
isServerNameValidated = validateServerName(subjectCN, hostName);
200174

@@ -530,4 +504,35 @@ private static InputStream fileToStream(String fname) throws IOException, SQLSer
530504
private static String getStringFromFile(String filePath) throws IOException {
531505
return new String(Files.readAllBytes(Paths.get(filePath)));
532506
}
507+
508+
/**
509+
* Securely parse the Common Name (CN) from the certificate subject using
510+
* LdapName/Rdn APIs and RFC2253 string representation to avoid mis-parsing
511+
* values that appear inside other attributes when canonical form is used.
512+
*/
513+
static String parseCommonNameSecure(X509Certificate cert) {
514+
try {
515+
X500Principal subjectPrincipal = cert.getSubjectX500Principal();
516+
String dn = subjectPrincipal.getName(X500Principal.RFC2253);
517+
518+
LdapName ldapDN = new LdapName(dn);
519+
for (Rdn rdn : ldapDN.getRdns()) {
520+
if ("CN".equalsIgnoreCase(rdn.getType())) {
521+
String cnValue = rdn.getValue().toString();
522+
return cnValue;
523+
}
524+
}
525+
526+
if (logger.isLoggable(Level.FINER)) {
527+
logger.finer(logContext + " No CN found in certificate subject");
528+
}
529+
return null;
530+
531+
} catch (Exception e) {
532+
if (logger.isLoggable(Level.WARNING)) {
533+
logger.warning(logContext + " Error parsing certificate: " + e.getMessage());
534+
}
535+
return null;
536+
}
537+
}
533538
}

src/samples/adaptive/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<dependency>
1616
<groupId>com.microsoft.sqlserver</groupId>
1717
<artifactId>mssql-jdbc</artifactId>
18-
<version>13.2.0.jre11</version>
18+
<version>13.2.1.jre11</version>
1919
</dependency>
2020
</dependencies>
2121
<profiles>

src/samples/alwaysencrypted/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<dependency>
1616
<groupId>com.microsoft.sqlserver</groupId>
1717
<artifactId>mssql-jdbc</artifactId>
18-
<version>13.2.0.jre11</version>
18+
<version>13.2.1.jre11</version>
1919
</dependency>
2020
</dependencies>
2121
<profiles>

src/samples/azureactivedirectoryauthentication/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
<dependency>
1515
<groupId>com.microsoft.sqlserver</groupId>
1616
<artifactId>mssql-jdbc</artifactId>
17-
<version>13.2.0.jre11</version>
17+
<version>13.2.1.jre11</version>
1818
</dependency>
1919
</dependencies>
2020
<profiles>

0 commit comments

Comments
 (0)