Skip to content

Commit 0394be1

Browse files
committed
mysqlnd MariaDB ed25519 authentication plugin
implementation for #14258. This requires libsodium 1.0.17 or later
1 parent 063d795 commit 0394be1

File tree

3 files changed

+145
-0
lines changed

3 files changed

+145
-0
lines changed

ext/mysqlnd/config.w32

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,22 @@ if (PHP_MYSQLND != "no") {
3838
ADD_EXTENSION_DEP('mysqlnd', 'hash');
3939
}
4040
}
41+
// Libsodium support
42+
ARG_WITH("mysqlnd-libsodium", "for libsodium support in mysqlnd", "no");
43+
if (PHP_MYSQLND_LIBSODIUM != "no") {
44+
if (CHECK_LIB("libsodium.lib", "mysqlnd") && CHECK_HEADER_ADD_INCLUDE("sodium.h", "CFLAGS")) {
45+
// Check version of libsodium >= 1.0.17
46+
var sodium_version_h = CHECK_HEADER_ADD_INCLUDE("sodium/version.h", "CFLAGS");
47+
if (sodium_version_h) {
48+
ADD_FLAG("CFLAGS", "/D PHP_MYSQLND_LIBSODIUM_MIN_VERSION=0x01001100");
49+
AC_DEFINE("MYSQLND_HAVE_LIBSODIUM", 1, "Define to 1 if mysqlnd has libsodium support.");
50+
} else {
51+
WARNING("libsodium not enabled for mysqlnd; sodium/version.h not found");
52+
}
53+
} else {
54+
WARNING("libsodium not enabled for mysqlnd; libraries and headers not found");
55+
}
56+
}
4157
PHP_INSTALL_HEADERS("", "ext/mysqlnd");
4258
}
4359
}

ext/mysqlnd/config9.m4

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,23 @@ if test "$PHP_MYSQLND" != "no" || test "$PHP_MYSQLND_ENABLED" = "yes"; then
7070
PHP_ADD_EXTENSION_DEP(mysqlnd, hash)
7171
])])
7272

73+
dnl -- Libsodium support --
74+
PHP_ARG_WITH([mysqlnd-libsodium],
75+
[whether to enable libsodium support in mysqlnd],
76+
[AS_HELP_STRING([--with-mysqlnd-libsodium], [Enable libsodium support in mysqlnd])],
77+
[no],
78+
[no])
79+
80+
if test "$PHP_MYSQLND_LIBSODIUM" != "no"; then
81+
PKG_CHECK_MODULES([LIBSODIUM], [libsodium >= 1.0.17], [
82+
AC_DEFINE([MYSQLND_HAVE_LIBSODIUM], [1], [Define to 1 if mysqlnd has libsodium support.])
83+
PHP_EVAL_LIBLINE([$LIBSODIUM_LIBS], [MYSQLND_SHARED_LIBADD])
84+
PHP_EVAL_INCLINE([$LIBSODIUM_CFLAGS])
85+
], [
86+
AC_MSG_ERROR([libsodium >= 1.0.17 library not found])
87+
])
88+
fi
89+
7390
PHP_INSTALL_HEADERS([ext/mysqlnd/])
7491
PHP_SUBST([MYSQLND_SHARED_LIBADD])
7592
fi

ext/mysqlnd/mysqlnd_auth.c

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@
2424
#include "mysqlnd_priv.h"
2525
#include "mysqlnd_charset.h"
2626
#include "mysqlnd_debug.h"
27+
#ifdef MYSQLND_HAVE_LIBSODIUM
28+
#include <sodium.h>
29+
#include <sodium/crypto_hash_sha512.h>
30+
#include <sodium/crypto_scalarmult_ed25519.h>
31+
#include <sodium/crypto_core_ed25519.h>
32+
#endif
2733

2834
static const char * const mysqlnd_old_passwd = "mysqlnd cannot connect to MySQL 4.1+ using the old insecure authentication. "
2935
"Please use an administration tool to reset your password with the command SET PASSWORD = PASSWORD('your_existing_password'). This will "
@@ -1324,6 +1330,109 @@ static struct st_mysqlnd_authentication_plugin mysqlnd_caching_sha2_auth_plugin
13241330
#endif
13251331

13261332

1333+
#ifdef MYSQLND_HAVE_LIBSODIUM
1334+
1335+
static zend_uchar *
1336+
mysqlnd_ed25519_auth_data(struct st_mysqlnd_authentication_plugin * self,
1337+
size_t * auth_data_len,
1338+
MYSQLND_CONN_DATA * conn, const char * const user, const char * const passwd,
1339+
const size_t passwd_len, zend_uchar * auth_plugin_data, const size_t auth_plugin_data_len,
1340+
const MYSQLND_SESSION_OPTIONS * const session_options,
1341+
const MYSQLND_PFC_DATA * const pfc_data,
1342+
const zend_ulong mysql_flags
1343+
)
1344+
{
1345+
zend_uchar *ret = NULL;
1346+
DBG_ENTER("mysqlnd_ed25519_auth_data");
1347+
DBG_INF_FMT("salt(%zu)=[%.*s]", auth_plugin_data_len, (int) auth_plugin_data_len, auth_plugin_data);
1348+
1349+
// Ensure the salt length is exactly 32 bytes
1350+
if (auth_plugin_data_len != 32) {
1351+
DBG_ERR_FMT("auth_plugin_data_len is %zu, expected 32", auth_plugin_data_len);
1352+
DBG_RETURN(NULL);
1353+
}
1354+
1355+
*auth_data_len = 0;
1356+
1357+
// Inline signature creation logic
1358+
unsigned char h[64], r[64], k[64];
1359+
unsigned char *sm = NULL;
1360+
unsigned char *s, *prefix;
1361+
1362+
sm = malloc(auth_plugin_data_len + 64);
1363+
if (!sm) {
1364+
DBG_RETURN(NULL);
1365+
}
1366+
1367+
// h = SHA512(password)
1368+
crypto_hash_sha512(h, (const unsigned char *)passwd, passwd_len);
1369+
1370+
// s = prune(h[0:31])
1371+
s = h;
1372+
s[0] &= 248;
1373+
s[31] &= 127;
1374+
s[31] |= 64;
1375+
1376+
// prefix = h[32:63]
1377+
prefix = h + 32;
1378+
1379+
// r = SHA512(prefix || M)
1380+
memcpy(sm + 32, prefix, 32);
1381+
memcpy(sm + 64, auth_plugin_data, auth_plugin_data_len);
1382+
crypto_hash_sha512(r, sm + 32, auth_plugin_data_len + 32);
1383+
1384+
// R = encoded point [r]B
1385+
crypto_core_ed25519_scalar_reduce(r, r);
1386+
crypto_scalarmult_ed25519_base_noclamp(sm, r);
1387+
1388+
// A = encoded point [s]B
1389+
crypto_scalarmult_ed25519_base_noclamp(sm + 32, s);
1390+
1391+
// k = SHA512(R || A || M)
1392+
crypto_hash_sha512(k, sm, auth_plugin_data_len + 64);
1393+
1394+
// S = (k * s + r) mod L
1395+
crypto_core_ed25519_scalar_reduce(k, k);
1396+
crypto_core_ed25519_scalar_mul(sm + 32, k, s);
1397+
crypto_core_ed25519_scalar_add(sm + 32, sm + 32, r);
1398+
1399+
ret = malloc(64);
1400+
if (ret) {
1401+
memcpy(ret, sm, 64);
1402+
*auth_data_len = 64;
1403+
}
1404+
free(sm);
1405+
1406+
DBG_RETURN(ret);
1407+
}
1408+
/* }}} */
1409+
1410+
1411+
1412+
static struct st_mysqlnd_authentication_plugin mysqlnd_ed25519_auth_plugin =
1413+
{
1414+
{
1415+
MYSQLND_PLUGIN_API_VERSION,
1416+
"auth_plugin_client_ed25519",
1417+
MYSQLND_VERSION_ID,
1418+
PHP_MYSQLND_VERSION,
1419+
"PHP License 3.01",
1420+
"Diego Dupin <[email protected]>",
1421+
{
1422+
NULL, /* no statistics , will be filled later if there are some */
1423+
NULL, /* no statistics */
1424+
},
1425+
{
1426+
NULL /* plugin shutdown */
1427+
}
1428+
},
1429+
{/* methods */
1430+
mysqlnd_ed25519_auth_data,
1431+
NULL
1432+
}
1433+
};
1434+
#endif
1435+
13271436
/* {{{ mysqlnd_register_builtin_authentication_plugins */
13281437
void
13291438
mysqlnd_register_builtin_authentication_plugins(void)
@@ -1334,5 +1443,8 @@ mysqlnd_register_builtin_authentication_plugins(void)
13341443
mysqlnd_plugin_register_ex((struct st_mysqlnd_plugin_header *) &mysqlnd_caching_sha2_auth_plugin);
13351444
mysqlnd_plugin_register_ex((struct st_mysqlnd_plugin_header *) &mysqlnd_sha256_authentication_plugin);
13361445
#endif
1446+
#ifdef MYSQLND_HAVE_LIBSODIUM
1447+
mysqlnd_plugin_register_ex((struct st_mysqlnd_plugin_header *) &mysqlnd_ed25519_auth_plugin);
1448+
#endif
13371449
}
13381450
/* }}} */

0 commit comments

Comments
 (0)