Skip to content

Commit

Permalink
TLS fingerprint
Browse files Browse the repository at this point in the history
Beside SHA1 fingerprint hash, Connector/C now also supports
SHA224 (OpenSSL and GnuTLS only), SHA256, SHA384 and SHA512
fingerprint hashes.
  • Loading branch information
9EOR9 authored and vuvova committed Feb 4, 2024
1 parent 3956415 commit 9aa15e7
Show file tree
Hide file tree
Showing 12 changed files with 189 additions and 63 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ CONFIGURE_FILE(${CC_SOURCE_DIR}/include/mariadb_version.h.in
INCLUDE_DIRECTORIES(${CC_BINARY_DIR}/include)

IF(WIN32)
SET(SYSTEM_LIBS ws2_32 advapi32 kernel32 shlwapi crypt32 ${LIBZ})
SET(SYSTEM_LIBS ws2_32 advapi32 kernel32 shlwapi crypt32 bcrypt ${LIBZ})
ELSE()
SET(SYSTEM_LIBS ${SYSTEM_LIBS} ${LIBPTHREAD} ${CMAKE_DL_LIBS} ${LIBM})
IF(ICONV_EXTERNAL)
Expand Down
24 changes: 4 additions & 20 deletions include/ma_crypt.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,34 +17,20 @@
51 Franklin St., Fifth Floor, Boston, MA 02110, USA
*/

#ifndef _ma_hash_h_
#define _ma_hash_h_
#ifndef _ma_crypt_h_
#define _ma_crypt_h_

#include <ma_hash.h>
#include <stddef.h>
#include <stdarg.h>

/*! Hash algorithms */
#define MA_HASH_MD5 1
#define MA_HASH_SHA1 2
#define MA_HASH_SHA224 3
#define MA_HASH_SHA256 4
#define MA_HASH_SHA384 5
#define MA_HASH_SHA512 6
#define MA_HASH_RIPEMD160 7
#define MA_HASH_MAX 8

/*! Hash digest sizes */
#define MA_MD5_HASH_SIZE 16
#define MA_SHA1_HASH_SIZE 20
#define MA_SHA224_HASH_SIZE 28
#define MA_SHA256_HASH_SIZE 32
#define MA_SHA384_HASH_SIZE 48
#define MA_SHA512_HASH_SIZE 64
#define MA_RIPEMD160_HASH_SIZE 20

#define MA_MAX_HASH_SIZE 64
/** \typedef MRL hash context */

#if defined(HAVE_WINCRYPT)
typedef void MA_HASH_CTX;
#elif defined(HAVE_OPENSSL)
Expand Down Expand Up @@ -123,8 +109,6 @@ static inline size_t ma_hash_digest_size(unsigned int hash_alg)
return MA_SHA384_HASH_SIZE;
case MA_HASH_SHA512:
return MA_SHA512_HASH_SIZE;
case MA_HASH_RIPEMD160:
return MA_RIPEMD160_HASH_SIZE;
default:
return 0;
}
Expand Down Expand Up @@ -152,4 +136,4 @@ static inline void ma_hash(unsigned int algorithm,
ma_hash_free(ctx);
}

#endif /* _ma_hash_h_ */
#endif /* _ma_crypt_h_ */
22 changes: 22 additions & 0 deletions include/ma_hash.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#ifndef _ma_hash_h_
#define _ma_hash_h_

/*! Hash algorithms */
#define MA_HASH_MD5 1
#define MA_HASH_SHA1 2
#define MA_HASH_SHA224 3
#define MA_HASH_SHA256 4
#define MA_HASH_SHA384 5
#define MA_HASH_SHA512 6

/*! Hash digest sizes */
#define MA_MD5_HASH_SIZE 16
#define MA_SHA1_HASH_SIZE 20
#define MA_SHA224_HASH_SIZE 28
#define MA_SHA256_HASH_SIZE 32
#define MA_SHA384_HASH_SIZE 48
#define MA_SHA512_HASH_SIZE 64

#define MA_MAX_HASH_SIZE 64

#endif
6 changes: 5 additions & 1 deletion include/ma_tls.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef _ma_tls_h_
#define _ma_tls_h_

#include <ma_hash.h>

enum enum_pvio_tls_type {
SSL_TYPE_DEFAULT=0,
#ifdef _WIN32
Expand Down Expand Up @@ -128,12 +130,14 @@ const char *ma_tls_get_cipher(MARIADB_TLS *ssl);
returns SHA1 finger print of server certificate
Parameter:
MARIADB_TLS MariaDB SSL container
hash_type hash_type as defined in ma_hash.h
fp buffer for fingerprint
fp_len buffer length
Returns:
actual size of finger print
*/
unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, char *fp, unsigned int fp_len);
unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, uint hash_type, char *fp, unsigned int fp_len);

/* ma_tls_get_protocol_version
returns protocol version number in use
Expand Down
4 changes: 4 additions & 0 deletions libmariadb/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,10 @@ IF(WIN32)
${CC_SOURCE_DIR}/win-iconv/win_iconv.c
win32_errmsg.c
win32_errmsg.h)
IF(WITH_SSL STREQUAL "SCHANNEL")
SET(LIBMARIADB_SOURCES ${LIBMARIADB_SOURCES}
secure/win_crypt.c)
ENDIF()
ELSE()
IF(ICONV_INCLUDE_DIR)
INCLUDE_DIRECTORIES(BEFORE ${ICONV_INCLUDE_DIR})
Expand Down
87 changes: 64 additions & 23 deletions libmariadb/ma_tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,15 @@
#include <ma_tls.h>
#include <mysql/client_plugin.h>
#include <mariadb/ma_io.h>
#include <ma_hash.h>

#ifdef HAVE_NONBLOCK
#include <mariadb_async.h>
#include <ma_context.h>
#endif

#define MAX_FINGERPRINT_LEN 128;

/* Errors should be handled via pvio callback function */
my_bool ma_tls_initialized= FALSE;
unsigned int mariadb_deinitialize_ssl= 1;
Expand Down Expand Up @@ -141,36 +144,74 @@ static signed char ma_hex2int(char c)
return -1;
}

static my_bool ma_pvio_tls_compare_fp(const char *cert_fp,
unsigned int cert_fp_len,
const char *fp, unsigned int fp_len)
#ifndef EVP_MAX_MD_SIZE
#define EVP_MAX_MD_SIZE 64
#endif

static my_bool ma_pvio_tls_compare_fp(MARIADB_TLS *ctls,
const char *cert_fp,
unsigned int cert_fp_len
)
{
char *p= (char *)fp,
*c;
const char fp[EVP_MAX_MD_SIZE];
unsigned int fp_len= EVP_MAX_MD_SIZE;
unsigned int hash_type;

char *p, *c;
uint hash_len;

/* check length without colons */
if (strchr(cert_fp, ':'))
hash_len= (uint)((strlen(cert_fp) + 1) / 3) * 2;
else
hash_len= (uint)strlen(cert_fp);

/* check hash size */
switch (hash_len) {
#ifndef DISABLE_WEAK_HASH
case MA_SHA1_HASH_SIZE * 2:
hash_type = MA_HASH_SHA1;
break;
#endif
case MA_SHA224_HASH_SIZE * 2:
hash_type = MA_HASH_SHA224;
break;
case MA_SHA256_HASH_SIZE * 2:
hash_type = MA_HASH_SHA256;
break;
case MA_SHA384_HASH_SIZE * 2:
hash_type = MA_HASH_SHA384;
break;
case MA_SHA512_HASH_SIZE * 2:
hash_type = MA_HASH_SHA512;
break;
default:
{
MYSQL* mysql = ctls->pvio->mysql;
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
ER(CR_SSL_CONNECTION_ERROR),
"Unknown or invalid fingerprint hash size detected");
return 1;
}
}

/* check length */
if (cert_fp_len != 20)
if (!ma_tls_get_finger_print(ctls, hash_type, (char *)fp, fp_len))
return 1;

/* We support two formats:
2 digits hex numbers, separated by colons (length=59)
20 * 2 digits hex numbers without separators (length = 40)
*/
if (fp_len != (strchr(fp, ':') ? 59 : 40))
return 1;
p= (char *)cert_fp;
c = (char *)fp;

for(c= (char *)cert_fp; c < cert_fp + cert_fp_len; c++)
for (p = (char*)cert_fp; p < cert_fp + cert_fp_len; c++, p += 2)
{
signed char d1, d2;
if (*p == ':')
p++;
if (p - fp > (int)fp_len -1)
if (p - cert_fp > (int)fp_len - 1)
return 1;
if ((d1 = ma_hex2int(*p)) == - 1 ||
(d2 = ma_hex2int(*(p+1))) == -1 ||
(char)(d1 * 16 + d2) != *c)
if ((d1 = ma_hex2int(*p)) == -1 ||
(d2 = ma_hex2int(*(p + 1))) == -1 ||
(char)(d1 * 16 + d2) != *c)
return 1;
p+= 2;
}
return 0;
}
Expand All @@ -184,10 +225,10 @@ my_bool ma_pvio_tls_check_fp(MARIADB_TLS *ctls, const char *fp, const char *fp_l

cert_fp= (char *)malloc(cert_fp_len);

if ((cert_fp_len= ma_tls_get_finger_print(ctls, cert_fp, cert_fp_len)) < 1)
goto end;
if (fp)
rc= ma_pvio_tls_compare_fp(cert_fp, cert_fp_len, fp, (unsigned int)strlen(fp));
{
rc = ma_pvio_tls_compare_fp(ctls, fp, (uint)strlen(fp));
}
else if (fp_list)
{
MA_FILE *fp;
Expand All @@ -205,7 +246,7 @@ my_bool ma_pvio_tls_check_fp(MARIADB_TLS *ctls, const char *fp, const char *fp_l
if (pos)
*pos= '\0';

if (!ma_pvio_tls_compare_fp(cert_fp, cert_fp_len, buff, (unsigned int)strlen(buff)))
if (!ma_pvio_tls_compare_fp(ctls, cert_fp, cert_fp_len))
{
/* finger print is valid: close file and exit */
ma_close(fp);
Expand Down
29 changes: 27 additions & 2 deletions libmariadb/secure/gnutls.c
Original file line number Diff line number Diff line change
Expand Up @@ -1391,18 +1391,43 @@ static int my_verify_callback(gnutls_session_t ssl)
return 0;
}

unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, char *fp, unsigned int len)
unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, uint hash_type, char *fp, unsigned int len)
{
MYSQL *mysql;
size_t fp_len= len;
const gnutls_datum_t *cert_list;
unsigned int cert_list_size;
gnutls_digest_algorithm_t hash_alg;

if (!ctls || !ctls->ssl)
return 0;

mysql= (MYSQL *)gnutls_session_get_ptr(ctls->ssl);

switch (hash_type)
{
case MA_HASH_SHA1:
hash_alg = GNUTLS_DIG_SHA1;
break;
case MA_HASH_SHA224:
hash_alg = GNUTLS_DIG_SHA224;
break;
case MA_HASH_SHA256:
hash_alg = GNUTLS_DIG_SHA256;
break;
case MA_HASH_SHA384:
hash_alg = GNUTLS_DIG_SHA384;
break;
case MA_HASH_SHA512:
hash_alg = GNUTLS_DIG_SHA512;
break;
default:
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
ER(CR_SSL_CONNECTION_ERROR),
"Cannot detect hash algorithm for fingerprint verification");
return 0;
}

cert_list = gnutls_certificate_get_peers (ctls->ssl, &cert_list_size);
if (cert_list == NULL)
{
Expand All @@ -1412,7 +1437,7 @@ unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, char *fp, unsigned int l
return 0;
}

if (gnutls_fingerprint(GNUTLS_DIG_SHA1, &cert_list[0], fp, &fp_len) == 0)
if (gnutls_fingerprint(hash_alg, &cert_list[0], fp, &fp_len) == 0)
return fp_len;
else
{
Expand Down
2 changes: 0 additions & 2 deletions libmariadb/secure/gnutls_crypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ static gnutls_digest_algorithm_t ma_hash_get_algorithm(unsigned int alg)
return GNUTLS_DIG_SHA384;
case MA_HASH_SHA512:
return GNUTLS_DIG_SHA512;
case MA_HASH_RIPEMD160:
return GNUTLS_DIG_RMD160;
default:
return GNUTLS_DIG_UNKNOWN;
}
Expand Down
4 changes: 3 additions & 1 deletion libmariadb/secure/ma_schannel.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@
#include <ma_common.h>
#include <ma_pvio.h>
#include <errmsg.h>
#include <ma_hash.h>


#include <wincrypt.h>
#include <wintrust.h>


#include <security.h>
#include <ma_crypt.h>

#include <schnlsp.h>
#undef SECURITY_WIN32
Expand All @@ -57,7 +59,7 @@ struct st_schannel {
DWORD IoBufferSize;
SecPkgContext_StreamSizes Sizes;
CtxtHandle hCtxt;

BCRYPT_ALG_HANDLE HashProv[MA_MAX_HASH_SIZE];
/* Cached data from the last read/decrypt call.*/
SecBuffer extraBuf; /* encrypted data read from server. */
SecBuffer dataBuf; /* decrypted but still unread data from server.*/
Expand Down
Loading

0 comments on commit 9aa15e7

Please sign in to comment.