1
0
mirror of https://github.com/mariadb-corporation/mariadb-connector-c.git synced 2025-08-10 01:02:57 +03:00

TLS fingerprint

Beside SHA1 fingerprint hash, Connector/C now also supports
SHA224 (OpenSSL and GnuTLS only), SHA256, SHA384 and SHA512
fingerprint hashes.
This commit is contained in:
Georg Richter
2023-08-31 08:21:13 +02:00
committed by Sergei Golubchik
parent 395641549a
commit 9aa15e72a7
12 changed files with 191 additions and 65 deletions

View File

@@ -382,7 +382,7 @@ CONFIGURE_FILE(${CC_SOURCE_DIR}/include/mariadb_version.h.in
INCLUDE_DIRECTORIES(${CC_BINARY_DIR}/include) INCLUDE_DIRECTORIES(${CC_BINARY_DIR}/include)
IF(WIN32) IF(WIN32)
SET(SYSTEM_LIBS ws2_32 advapi32 kernel32 shlwapi crypt32 ${LIBZ}) SET(SYSTEM_LIBS ws2_32 advapi32 kernel32 shlwapi crypt32 bcrypt ${LIBZ})
ELSE() ELSE()
SET(SYSTEM_LIBS ${SYSTEM_LIBS} ${LIBPTHREAD} ${CMAKE_DL_LIBS} ${LIBM}) SET(SYSTEM_LIBS ${SYSTEM_LIBS} ${LIBPTHREAD} ${CMAKE_DL_LIBS} ${LIBM})
IF(ICONV_EXTERNAL) IF(ICONV_EXTERNAL)

View File

@@ -17,34 +17,20 @@
51 Franklin St., Fifth Floor, Boston, MA 02110, USA 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
*/ */
#ifndef _ma_hash_h_ #ifndef _ma_crypt_h_
#define _ma_hash_h_ #define _ma_crypt_h_
#include <ma_hash.h>
#include <stddef.h> #include <stddef.h>
#include <stdarg.h> #include <stdarg.h>
/*! Hash algorithms */ /*! 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_RIPEMD160 7
#define MA_HASH_MAX 8 #define MA_HASH_MAX 8
/*! Hash digest sizes */ /*! 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_RIPEMD160_HASH_SIZE 20
#define MA_MAX_HASH_SIZE 64
/** \typedef MRL hash context */
#if defined(HAVE_WINCRYPT) #if defined(HAVE_WINCRYPT)
typedef void MA_HASH_CTX; typedef void MA_HASH_CTX;
#elif defined(HAVE_OPENSSL) #elif defined(HAVE_OPENSSL)
@@ -123,8 +109,6 @@ static inline size_t ma_hash_digest_size(unsigned int hash_alg)
return MA_SHA384_HASH_SIZE; return MA_SHA384_HASH_SIZE;
case MA_HASH_SHA512: case MA_HASH_SHA512:
return MA_SHA512_HASH_SIZE; return MA_SHA512_HASH_SIZE;
case MA_HASH_RIPEMD160:
return MA_RIPEMD160_HASH_SIZE;
default: default:
return 0; return 0;
} }
@@ -152,4 +136,4 @@ static inline void ma_hash(unsigned int algorithm,
ma_hash_free(ctx); ma_hash_free(ctx);
} }
#endif /* _ma_hash_h_ */ #endif /* _ma_crypt_h_ */

22
include/ma_hash.h Normal file
View File

@@ -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

View File

@@ -1,6 +1,8 @@
#ifndef _ma_tls_h_ #ifndef _ma_tls_h_
#define _ma_tls_h_ #define _ma_tls_h_
#include <ma_hash.h>
enum enum_pvio_tls_type { enum enum_pvio_tls_type {
SSL_TYPE_DEFAULT=0, SSL_TYPE_DEFAULT=0,
#ifdef _WIN32 #ifdef _WIN32
@@ -128,12 +130,14 @@ const char *ma_tls_get_cipher(MARIADB_TLS *ssl);
returns SHA1 finger print of server certificate returns SHA1 finger print of server certificate
Parameter: Parameter:
MARIADB_TLS MariaDB SSL container MARIADB_TLS MariaDB SSL container
hash_type hash_type as defined in ma_hash.h
fp buffer for fingerprint fp buffer for fingerprint
fp_len buffer length fp_len buffer length
Returns: Returns:
actual size of finger print 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 /* ma_tls_get_protocol_version
returns protocol version number in use returns protocol version number in use

View File

@@ -344,6 +344,10 @@ IF(WIN32)
${CC_SOURCE_DIR}/win-iconv/win_iconv.c ${CC_SOURCE_DIR}/win-iconv/win_iconv.c
win32_errmsg.c win32_errmsg.c
win32_errmsg.h) win32_errmsg.h)
IF(WITH_SSL STREQUAL "SCHANNEL")
SET(LIBMARIADB_SOURCES ${LIBMARIADB_SOURCES}
secure/win_crypt.c)
ENDIF()
ELSE() ELSE()
IF(ICONV_INCLUDE_DIR) IF(ICONV_INCLUDE_DIR)
INCLUDE_DIRECTORIES(BEFORE ${ICONV_INCLUDE_DIR}) INCLUDE_DIRECTORIES(BEFORE ${ICONV_INCLUDE_DIR})

View File

@@ -41,12 +41,15 @@
#include <ma_tls.h> #include <ma_tls.h>
#include <mysql/client_plugin.h> #include <mysql/client_plugin.h>
#include <mariadb/ma_io.h> #include <mariadb/ma_io.h>
#include <ma_hash.h>
#ifdef HAVE_NONBLOCK #ifdef HAVE_NONBLOCK
#include <mariadb_async.h> #include <mariadb_async.h>
#include <ma_context.h> #include <ma_context.h>
#endif #endif
#define MAX_FINGERPRINT_LEN 128;
/* Errors should be handled via pvio callback function */ /* Errors should be handled via pvio callback function */
my_bool ma_tls_initialized= FALSE; my_bool ma_tls_initialized= FALSE;
unsigned int mariadb_deinitialize_ssl= 1; unsigned int mariadb_deinitialize_ssl= 1;
@@ -141,36 +144,74 @@ static signed char ma_hex2int(char c)
return -1; return -1;
} }
static my_bool ma_pvio_tls_compare_fp(const char *cert_fp, #ifndef EVP_MAX_MD_SIZE
unsigned int cert_fp_len, #define EVP_MAX_MD_SIZE 64
const char *fp, unsigned int fp_len) #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, const char fp[EVP_MAX_MD_SIZE];
*c; unsigned int fp_len= EVP_MAX_MD_SIZE;
unsigned int hash_type;
/* check length */ char *p, *c;
if (cert_fp_len != 20) 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;
}
}
if (!ma_tls_get_finger_print(ctls, hash_type, (char *)fp, fp_len))
return 1; return 1;
/* We support two formats: p= (char *)cert_fp;
2 digits hex numbers, separated by colons (length=59) c = (char *)fp;
20 * 2 digits hex numbers without separators (length = 40)
*/
if (fp_len != (strchr(fp, ':') ? 59 : 40))
return 1;
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; signed char d1, d2;
if (*p == ':') if (*p == ':')
p++; p++;
if (p - fp > (int)fp_len -1) if (p - cert_fp > (int)fp_len - 1)
return 1; return 1;
if ((d1 = ma_hex2int(*p)) == - 1 || if ((d1 = ma_hex2int(*p)) == -1 ||
(d2 = ma_hex2int(*(p+1))) == -1 || (d2 = ma_hex2int(*(p + 1))) == -1 ||
(char)(d1 * 16 + d2) != *c) (char)(d1 * 16 + d2) != *c)
return 1; return 1;
p+= 2;
} }
return 0; return 0;
} }
@@ -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); 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) 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) else if (fp_list)
{ {
MA_FILE *fp; MA_FILE *fp;
@@ -205,7 +246,7 @@ my_bool ma_pvio_tls_check_fp(MARIADB_TLS *ctls, const char *fp, const char *fp_l
if (pos) if (pos)
*pos= '\0'; *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 */ /* finger print is valid: close file and exit */
ma_close(fp); ma_close(fp);

View File

@@ -1391,18 +1391,43 @@ static int my_verify_callback(gnutls_session_t ssl)
return 0; 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; MYSQL *mysql;
size_t fp_len= len; size_t fp_len= len;
const gnutls_datum_t *cert_list; const gnutls_datum_t *cert_list;
unsigned int cert_list_size; unsigned int cert_list_size;
gnutls_digest_algorithm_t hash_alg;
if (!ctls || !ctls->ssl) if (!ctls || !ctls->ssl)
return 0; return 0;
mysql= (MYSQL *)gnutls_session_get_ptr(ctls->ssl); 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); cert_list = gnutls_certificate_get_peers (ctls->ssl, &cert_list_size);
if (cert_list == NULL) if (cert_list == NULL)
{ {
@@ -1412,7 +1437,7 @@ unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, char *fp, unsigned int l
return 0; 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; return fp_len;
else else
{ {

View File

@@ -34,8 +34,6 @@ static gnutls_digest_algorithm_t ma_hash_get_algorithm(unsigned int alg)
return GNUTLS_DIG_SHA384; return GNUTLS_DIG_SHA384;
case MA_HASH_SHA512: case MA_HASH_SHA512:
return GNUTLS_DIG_SHA512; return GNUTLS_DIG_SHA512;
case MA_HASH_RIPEMD160:
return GNUTLS_DIG_RMD160;
default: default:
return GNUTLS_DIG_UNKNOWN; return GNUTLS_DIG_UNKNOWN;
} }

View File

@@ -28,6 +28,7 @@
#include <ma_common.h> #include <ma_common.h>
#include <ma_pvio.h> #include <ma_pvio.h>
#include <errmsg.h> #include <errmsg.h>
#include <ma_hash.h>
#include <wincrypt.h> #include <wincrypt.h>
@@ -35,6 +36,7 @@
#include <security.h> #include <security.h>
#include <ma_crypt.h>
#include <schnlsp.h> #include <schnlsp.h>
#undef SECURITY_WIN32 #undef SECURITY_WIN32
@@ -57,7 +59,7 @@ struct st_schannel {
DWORD IoBufferSize; DWORD IoBufferSize;
SecPkgContext_StreamSizes Sizes; SecPkgContext_StreamSizes Sizes;
CtxtHandle hCtxt; CtxtHandle hCtxt;
BCRYPT_ALG_HANDLE HashProv[MA_MAX_HASH_SIZE];
/* Cached data from the last read/decrypt call.*/ /* Cached data from the last read/decrypt call.*/
SecBuffer extraBuf; /* encrypted data read from server. */ SecBuffer extraBuf; /* encrypted data read from server. */
SecBuffer dataBuf; /* decrypted but still unread data from server.*/ SecBuffer dataBuf; /* decrypted but still unread data from server.*/

View File

@@ -29,6 +29,7 @@
#include <openssl/err.h> /* error reporting */ #include <openssl/err.h> /* error reporting */
#include <openssl/conf.h> #include <openssl/conf.h>
#include <openssl/md4.h> #include <openssl/md4.h>
#include <ma_tls.h>
#if defined(_WIN32) && !defined(_OPENSSL_Applink) && defined(HAVE_OPENSSL_APPLINK_C) #if defined(_WIN32) && !defined(_OPENSSL_Applink) && defined(HAVE_OPENSSL_APPLINK_C)
#include <openssl/applink.c> #include <openssl/applink.c>
@@ -729,16 +730,49 @@ const char *ma_tls_get_cipher(MARIADB_TLS *ctls)
return SSL_get_cipher_name(ctls->ssl); return SSL_get_cipher_name(ctls->ssl);
} }
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)
{ {
X509 *cert= NULL; X509 *cert= NULL;
MYSQL *mysql; MYSQL *mysql;
unsigned int fp_len; unsigned int fp_len;
const EVP_MD *hash_alg;
if (!ctls || !ctls->ssl) if (!ctls || !ctls->ssl)
return 0; return 0;
mysql= SSL_get_app_data(ctls->ssl); mysql = SSL_get_app_data(ctls->ssl);
if (len < EVP_MAX_MD_SIZE)
{
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
ER(CR_SSL_CONNECTION_ERROR),
"Finger print buffer too small");
return 0;
}
switch (hash_type)
{
case MA_HASH_SHA1:
hash_alg = EVP_sha1();
break;
case MA_HASH_SHA224:
hash_alg = EVP_sha224();
break;
case MA_HASH_SHA256:
hash_alg = EVP_sha256();
break;
case MA_HASH_SHA384:
hash_alg = EVP_sha384();
break;
case MA_HASH_SHA512:
hash_alg = EVP_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;
}
if (!(cert= SSL_get_peer_certificate(ctls->ssl))) if (!(cert= SSL_get_peer_certificate(ctls->ssl)))
{ {
@@ -748,14 +782,7 @@ unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, char *fp, unsigned int l
goto end; goto end;
} }
if (len < EVP_MAX_MD_SIZE) if (!X509_digest(cert, hash_alg, (unsigned char *)fp, &fp_len))
{
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
ER(CR_SSL_CONNECTION_ERROR),
"Finger print buffer too small");
goto end;
}
if (!X509_digest(cert, EVP_sha1(), (unsigned char *)fp, &fp_len))
{ {
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
ER(CR_SSL_CONNECTION_ERROR), ER(CR_SSL_CONNECTION_ERROR),

View File

@@ -36,8 +36,6 @@ static const EVP_MD *ma_hash_get_algorithm(unsigned int alg)
return EVP_sha384(); return EVP_sha384();
case MA_HASH_SHA512: case MA_HASH_SHA512:
return EVP_sha512(); return EVP_sha512();
case MA_HASH_RIPEMD160:
return EVP_ripemd160();
default: default:
return NULL; return NULL;
} }

View File

@@ -20,6 +20,9 @@
#include "ma_schannel.h" #include "ma_schannel.h"
#include "schannel_certs.h" #include "schannel_certs.h"
#include <string.h> #include <string.h>
#include <ma_crypt.h>
#include <wincrypt.h>
#include <bcrypt.h>
extern my_bool ma_tls_initialized; extern my_bool ma_tls_initialized;
char tls_library_version[] = "Schannel"; char tls_library_version[] = "Schannel";
@@ -550,15 +553,33 @@ const char *ma_tls_get_cipher(MARIADB_TLS *ctls)
return cipher_name(&CipherInfo); return cipher_name(&CipherInfo);
} }
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)
{ {
MA_HASH_CTX* hash_ctx;
SC_CTX *sctx= (SC_CTX *)ctls->ssl; SC_CTX *sctx= (SC_CTX *)ctls->ssl;
PCCERT_CONTEXT pRemoteCertContext = NULL; PCCERT_CONTEXT pRemoteCertContext = NULL;
int rc= 0;
if (hash_type == MA_HASH_SHA224)
{
MYSQL *mysql = ctls->pvio->mysql;
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
ER(CR_SSL_CONNECTION_ERROR),
"SHA224 hash for fingerprint verification is not supported in Schannel");
return 0;
}
if (QueryContextAttributes(&sctx->hCtxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&pRemoteCertContext) != SEC_E_OK) if (QueryContextAttributes(&sctx->hCtxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&pRemoteCertContext) != SEC_E_OK)
return 0; return 0;
CertGetCertificateContextProperty(pRemoteCertContext, CERT_HASH_PROP_ID, fp, (DWORD *)&len);
hash_ctx = ma_hash_new(hash_type);
ma_hash_input(hash_ctx, pRemoteCertContext->pbCertEncoded, pRemoteCertContext->cbCertEncoded);
ma_hash_result(hash_ctx, fp);
ma_hash_free(hash_ctx);
CertFreeCertificateContext(pRemoteCertContext); CertFreeCertificateContext(pRemoteCertContext);
return len; return (uint)ma_hash_digest_size(hash_type);
} }
void ma_tls_set_connection(MYSQL *mysql __attribute__((unused))) void ma_tls_set_connection(MYSQL *mysql __attribute__((unused)))