1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2024-11-08 16:57:16 +01:00
SqMod/vendor/MDBC/libmariadb/secure/gnutls.c

1464 lines
41 KiB
C
Raw Normal View History

/************************************************************************************
Copyright (C) 2014 MariaDB Corporation AB
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not see <http://www.gnu.org/licenses>
or write to the Free Software Foundation, Inc.,
51 Franklin St., Fifth Floor, Boston, MA 02110, USA
*************************************************************************************/
#ifdef HAVE_GNUTLS
#include <ma_global.h>
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include <gnutls/abstract.h>
#include <ma_sys.h>
#include <ma_common.h>
#include <ma_pvio.h>
#include <errmsg.h>
#include <ma_pthread.h>
#include <mysql/client_plugin.h>
#include <string.h>
#include <ma_tls.h>
#include <mariadb_async.h>
#include <ma_context.h>
pthread_mutex_t LOCK_gnutls_config;
extern my_bool ma_tls_initialized;
extern unsigned int mariadb_deinitialize_ssl;
enum ma_pem_type {
MA_TLS_PEM_CERT= 0,
MA_TLS_PEM_KEY,
MA_TLS_PEM_CA,
MA_TLS_PEM_CRL
};
static int my_verify_callback(gnutls_session_t ssl);
char tls_library_version[TLS_VERSION_LENGTH];
struct st_gnutls_data {
MYSQL *mysql;
gnutls_privkey_t key;
gnutls_pcert_st cert;
};
struct st_cipher_map {
unsigned char sid[2];
const char *iana_name;
const char *openssl_name;
const char *gnutls_name;
};
const struct st_cipher_map tls_ciphers[]=
{
{ {0x00, 0x01},
"TLS_RSA_WITH_NULL_MD5",
NULL,
"TLS_RSA_NULL_MD5"},
{ {0x00, 0x02},
"TLS_RSA_WITH_NULL_SHA",
NULL,
"TLS_RSA_NULL_SHA1"},
{ {0x00, 0x3B},
"TLS_RSA_WITH_NULL_SHA256",
NULL,
"TLS_RSA_NULL_SHA256"},
{ {0x00, 0x05},
"TLS_RSA_WITH_RC4_128_SHA",
NULL,
"TLS_RSA_ARCFOUR_128_SHA1"},
{ {0x00, 0x04},
"TLS_RSA_WITH_RC4_128_MD5",
NULL,
"TLS_RSA_ARCFOUR_128_MD5"},
{ {0x00, 0x0A},
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
"DES-CBC3-SHA",
"TLS_RSA_3DES_EDE_CBC_SHA1"},
{ {0x00, 0x2F},
"TLS_RSA_WITH_AES_128_CBC_SHA",
"AES128-SHA",
"TLS_RSA_AES_128_CBC_SHA1"},
{ {0x00, 0x35},
"TLS_RSA_WITH_AES_256_CBC_SHA",
"AES256-SHA",
"TLS_RSA_AES_256_CBC_SHA1"},
{ {0x00, 0xBA},
"TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256",
"CAMELLIA128-SHA256",
"TLS_RSA_CAMELLIA_128_CBC_SHA256"},
{ {0x00, 0xC0},
"TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256",
NULL,
"TLS_RSA_CAMELLIA_256_CBC_SHA256"},
{ {0x00, 0x41},
"TLS_RSA_WITH_CAMELLIA_128_CBC_SHA",
"CAMELLIA128-SHA",
"TLS_RSA_CAMELLIA_128_CBC_SHA1"},
{ {0x00, 0x84},
"TLS_RSA_WITH_CAMELLIA_256_CBC_SHA",
"CAMELLIA256-SHA",
"TLS_RSA_CAMELLIA_256_CBC_SHA1"},
{ {0x00, 0x3C},
"TLS_RSA_WITH_AES_128_CBC_SHA256",
"AES128-SHA256",
"TLS_RSA_AES_128_CBC_SHA256"},
{ {0x00, 0x3D},
"TLS_RSA_WITH_AES_256_CBC_SHA256",
"AES256-SHA256",
"TLS_RSA_AES_256_CBC_SHA256"},
{ {0x00, 0x9C},
"TLS_RSA_WITH_AES_128_GCM_SHA256",
"AES128-GCM-SHA256",
"TLS_RSA_AES_128_GCM_SHA256"},
{ {0x00, 0x9D},
"TLS_RSA_WITH_AES_256_GCM_SHA384",
"AES256-GCM-SHA384",
"TLS_RSA_AES_256_GCM_SHA384"},
{ {0xC0, 0x7A},
"TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256",
NULL,
"TLS_RSA_CAMELLIA_128_GCM_SHA256"},
{ {0xC0, 0x7B},
"TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384",
NULL,
"TLS_RSA_CAMELLIA_256_GCM_SHA384"},
{ {0xC0, 0x9C},
"TLS_RSA_WITH_AES_128_CCM",
NULL,
"TLS_RSA_AES_128_CCM"},
{ {0xC0, 0x9D},
"TLS_RSA_WITH_AES_256_CCM",
NULL,
"TLS_RSA_AES_256_CCM"},
{ {0xC0, 0xA0},
"TLS_RSA_WITH_AES_128_CCM_8",
NULL,
"TLS_RSA_AES_128_CCM_8"},
{ {0xC0, 0xA1},
"TLS_RSA_WITH_AES_256_CCM_8",
NULL,
"TLS_RSA_AES_256_CCM_8"},
{ {0x00, 0x66},
"TLS_DHE_DSS_WITH_RC4_128_SHA",
NULL,
"TLS_DHE_DSS_ARCFOUR_128_SHA1"},
{ {0x00, 0x13},
"TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
NULL,
"TLS_DHE_DSS_3DES_EDE_CBC_SHA1"},
{ {0x00, 0x32},
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
NULL,
"TLS_DHE_DSS_AES_128_CBC_SHA1"},
{ {0x00, 0x38},
"TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
NULL,
"TLS_DHE_DSS_AES_256_CBC_SHA1"},
{ {0x00, 0xBD},
"TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256",
NULL,
"TLS_DHE_DSS_CAMELLIA_128_CBC_SHA256"},
{ {0x00, 0xC3},
"TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256",
NULL,
"TLS_DHE_DSS_CAMELLIA_256_CBC_SHA256"},
{ {0x00, 0x44},
"TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA",
NULL,
"TLS_DHE_DSS_CAMELLIA_128_CBC_SHA1"},
{ {0x00, 0x87},
"TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA",
NULL,
"TLS_DHE_DSS_CAMELLIA_256_CBC_SHA1"},
{ {0x00, 0x40},
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA256",
NULL,
"TLS_DHE_DSS_AES_128_CBC_SHA256"},
{ {0x00, 0x6A},
"TLS_DHE_DSS_WITH_AES_256_CBC_SHA256",
NULL,
"TLS_DHE_DSS_AES_256_CBC_SHA256"},
{ {0x00, 0xA2},
"TLS_DHE_DSS_WITH_AES_128_GCM_SHA256",
NULL,
"TLS_DHE_DSS_AES_128_GCM_SHA256"},
{ {0x00, 0xA3},
"TLS_DHE_DSS_WITH_AES_256_GCM_SHA384",
NULL,
"TLS_DHE_DSS_AES_256_GCM_SHA384"},
{ {0xC0, 0x80},
"TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256",
NULL,
"TLS_DHE_DSS_CAMELLIA_128_GCM_SHA256"},
{ {0xC0, 0x81},
"TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384",
NULL,
"TLS_DHE_DSS_CAMELLIA_256_GCM_SHA384"},
{ {0x00, 0x16},
"TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
"EDH-RSA-DES-CBC3-SHA",
"TLS_DHE_RSA_3DES_EDE_CBC_SHA1"},
{ {0x00, 0x33},
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
"DHE-RSA-AES128-SHA",
"TLS_DHE_RSA_AES_128_CBC_SHA1"},
{ {0x00, 0x39},
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
"DHE-RSA-AES256-SHA",
"TLS_DHE_RSA_AES_256_CBC_SHA1"},
{ {0x00, 0xBE},
"TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256",
NULL,
"TLS_DHE_RSA_CAMELLIA_128_CBC_SHA256"},
{ {0x00, 0xC4},
"TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256",
NULL,
"TLS_DHE_RSA_CAMELLIA_256_CBC_SHA256"},
{ {0x00, 0x45},
"TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA",
"DHE-RSA-CAMELLIA128-SHA",
"TLS_DHE_RSA_CAMELLIA_128_CBC_SHA1"},
{ {0x00, 0x88},
"TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA",
"DHE-RSA-CAMELLIA256-SHA",
"TLS_DHE_RSA_CAMELLIA_256_CBC_SHA1"},
{ {0x00, 0x67},
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
"DHE-RSA-AES128-SHA256",
"TLS_DHE_RSA_AES_128_CBC_SHA256"},
{ {0x00, 0x6B},
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
"DHE-RSA-AES256-SHA256",
"TLS_DHE_RSA_AES_256_CBC_SHA256"},
{ {0x00, 0x9E},
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
"DHE-RSA-AES128-GCM-SHA256",
"TLS_DHE_RSA_AES_128_GCM_SHA256"},
{ {0x00, 0x9F},
"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
"DHE-RSA-AES256-GCM-SHA384",
"TLS_DHE_RSA_AES_256_GCM_SHA384"},
{ {0xC0, 0x7C},
"TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256",
NULL,
"TLS_DHE_RSA_CAMELLIA_128_GCM_SHA256"},
{ {0xC0, 0x7D},
"TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384",
NULL,
"TLS_DHE_RSA_CAMELLIA_256_GCM_SHA384"},
{ {0xCC, 0xAA},
"TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
"DHE-RSA-CHACHA20-POLY1305",
"TLS_DHE_RSA_CHACHA20_POLY1305"},
{ {0xC0, 0x9E},
"TLS_DHE_RSA_WITH_AES_128_CCM",
NULL,
"TLS_DHE_RSA_AES_128_CCM"},
{ {0xC0, 0x9F},
"TLS_DHE_RSA_WITH_AES_256_CCM",
NULL,
"TLS_DHE_RSA_AES_256_CCM"},
{ {0xC0, 0xA2},
"TLS_DHE_RSA_WITH_AES_128_CCM_8",
NULL,
"TLS_DHE_RSA_AES_128_CCM_8"},
{ {0xC0, 0xA3},
"TLS_DHE_RSA_WITH_AES_256_CCM_8",
NULL,
"TLS_DHE_RSA_AES_256_CCM_8"},
{ {0xC0, 0x10},
"TLS_ECDHE_RSA_WITH_",
NULL,
"TLS_ECDHE_RSA_NULL_SHA1"},
{ {0xC0, 0x12},
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
"ECDHE-RSA-DES-CBC3-SHA",
"TLS_ECDHE_RSA_3DES_EDE_CBC_SHA1"},
{ {0xC0, 0x13},
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
"ECDHE-RSA-AES128-SHA",
"TLS_ECDHE_RSA_AES_128_CBC_SHA1"},
{ {0xC0, 0x14},
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
"ECDHE-RSA-AES256-SHA",
"TLS_ECDHE_RSA_AES_256_CBC_SHA1"},
{ {0xC0, 0x28},
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
"ECDHE-RSA-AES256-SHA384",
"TLS_ECDHE_RSA_AES_256_CBC_SHA384"},
{ {0xC0, 0x11},
"TLS_ECDHE_RSA_WITH_RC4_128_SHA",
NULL,
"TLS_ECDHE_RSA_ARCFOUR_128_SHA1"},
{ {0xC0, 0x76},
"TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256",
NULL,
"TLS_ECDHE_RSA_CAMELLIA_128_CBC_SHA256"},
{ {0xC0, 0x77},
"TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384",
NULL,
"TLS_ECDHE_RSA_CAMELLIA_256_CBC_SHA384"},
{ {0xC0, 0x06},
"TLS_ECDHE_ECDSA_WITH_",
NULL,
"TLS_ECDHE_ECDSA_NULL_SHA1"},
{ {0xC0, 0x08},
"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
"ECDHE-ECDSA-DES-CBC3-SHA",
"TLS_ECDHE_ECDSA_3DES_EDE_CBC_SHA1"},
{ {0xC0, 0x09},
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
"ECDHE-ECDSA-AES128-SHA",
"TLS_ECDHE_ECDSA_AES_128_CBC_SHA1"},
{ {0xC0, 0x0A},
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
"ECDHE-ECDSA-AES256-SHA",
"TLS_ECDHE_ECDSA_AES_256_CBC_SHA1"},
{ {0xC0, 0x07},
"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
NULL,
"TLS_ECDHE_ECDSA_ARCFOUR_128_SHA1"},
{ {0xC0, 0x72},
"TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256",
NULL,
"TLS_ECDHE_ECDSA_CAMELLIA_128_CBC_SHA256"},
{ {0xC0, 0x73},
"TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384",
NULL,
"TLS_ECDHE_ECDSA_CAMELLIA_256_CBC_SHA384"},
{ {0xC0, 0x23},
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
"ECDHE-ECDSA-AES128-SHA256",
"TLS_ECDHE_ECDSA_AES_128_CBC_SHA256"},
{ {0xC0, 0x27},
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
"ECDHE-RSA-AES128-SHA256",
"TLS_ECDHE_RSA_AES_128_CBC_SHA256"},
{ {0xC0, 0x86},
"TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256",
NULL,
"TLS_ECDHE_ECDSA_CAMELLIA_128_GCM_SHA256"},
{ {0xC0, 0x87},
"TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384",
NULL,
"TLS_ECDHE_ECDSA_CAMELLIA_256_GCM_SHA384"},
{ {0xC0, 0x2B},
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"ECDHE-ECDSA-AES128-GCM-SHA256",
"TLS_ECDHE_ECDSA_AES_128_GCM_SHA256"},
{ {0xC0, 0x2C},
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"ECDHE-ECDSA-AES256-GCM-SHA384",
"TLS_ECDHE_ECDSA_AES_256_GCM_SHA384"},
{ {0xC0, 0x2F},
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"ECDHE-RSA-AES128-GCM-SHA256",
"TLS_ECDHE_RSA_AES_128_GCM_SHA256"},
{ {0xC0, 0x30},
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"ECDHE-RSA-AES256-GCM-SHA384",
"TLS_ECDHE_RSA_AES_256_GCM_SHA384"},
{ {0xC0, 0x24},
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
"ECDHE-ECDSA-AES256-SHA384",
"TLS_ECDHE_ECDSA_AES_256_CBC_SHA384"},
{ {0xC0, 0x8A},
"TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256",
NULL,
"TLS_ECDHE_RSA_CAMELLIA_128_GCM_SHA256"},
{ {0xC0, 0x8B},
"TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384",
NULL,
"TLS_ECDHE_RSA_CAMELLIA_256_GCM_SHA384"},
{ {0xCC, 0xA8},
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
"ECDHE-RSA-CHACHA20-POLY1305",
"TLS_ECDHE_RSA_CHACHA20_POLY1305"},
{ {0xCC, 0xA9},
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
"ECDHE-ECDSA-CHACHA20-POLY1305",
"TLS_ECDHE_ECDSA_CHACHA20_POLY1305"},
{ {0xC0, 0xAC},
"TLS_ECDHE_ECDSA_WITH_AES_128_CCM",
NULL,
"TLS_ECDHE_ECDSA_AES_128_CCM"},
{ {0xC0, 0xAD},
"TLS_ECDHE_ECDSA_WITH_AES_256_CCM",
NULL,
"TLS_ECDHE_ECDSA_AES_256_CCM"},
{ {0xC0, 0xAE},
"TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8",
NULL,
"TLS_ECDHE_ECDSA_AES_128_CCM_8"},
{ {0xC0, 0xAF},
"TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8",
NULL,
"TLS_ECDHE_ECDSA_AES_256_CCM_8"},
{ {0xC0, 0x34},
"TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA",
"ECDHE-PSK-3DES-EDE-CBC-SHA",
"TLS_ECDHE_PSK_3DES_EDE_CBC_SHA1"},
{ {0xC0, 0x35},
"TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA",
"ECDHE-PSK-AES128-CBC-SHA",
"TLS_ECDHE_PSK_AES_128_CBC_SHA1"},
{ {0xC0, 0x36},
"TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA",
"ECDHE-PSK-AES256-CBC-SHA",
"TLS_ECDHE_PSK_AES_256_CBC_SHA1"},
{ {0xC0, 0x37},
"TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256",
"ECDHE-PSK-AES128-CBC-SHA256",
"TLS_ECDHE_PSK_AES_128_CBC_SHA256"},
{ {0xC0, 0x38},
"TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384",
"ECDHE-PSK-AES256-CBC-SHA384",
"TLS_ECDHE_PSK_AES_256_CBC_SHA384"},
{ {0xC0, 0x33},
"TLS_ECDHE_PSK_WITH_RC4_128_SHA",
NULL,
"TLS_ECDHE_PSK_ARCFOUR_128_SHA1"},
{ {0xC0, 0x39},
"TLS_ECDHE_PSK_WITH_NULL_SHA",
NULL,
"TLS_ECDHE_PSK_NULL_SHA1"},
{ {0xC0, 0x3A},
"TLS_ECDHE_PSK_WITH_NULL_SHA256",
NULL,
"TLS_ECDHE_PSK_NULL_SHA256"},
{ {0xC0, 0x3B},
"TLS_ECDHE_PSK_WITH_NULL_SHA384",
NULL,
"TLS_ECDHE_PSK_NULL_SHA384"},
{ {0xC0, 0x9A},
"TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256",
NULL,
"TLS_ECDHE_PSK_CAMELLIA_128_CBC_SHA256"},
{ {0xC0, 0x9B},
"TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384",
NULL,
"TLS_ECDHE_PSK_CAMELLIA_256_CBC_SHA384"},
{ {0x00, 0x8A},
"TLS_PSK_WITH_RC4_128_SHA",
NULL,
"TLS_PSK_ARCFOUR_128_SHA1"},
{ {0x00, 0x8B},
"TLS_PSK_WITH_3DES_EDE_CBC_SHA",
"PSK-3DES-EDE-CBC-SHA",
"TLS_PSK_3DES_EDE_CBC_SHA1"},
{ {0x00, 0x8C},
"TLS_PSK_WITH_AES_128_CBC_SHA",
"PSK-AES128-CBC-SHA",
"TLS_PSK_AES_128_CBC_SHA1"},
{ {0x00, 0x8D},
"TLS_PSK_WITH_AES_256_CBC_SHA",
"PSK-AES256-CBC-SHA",
"TLS_PSK_AES_256_CBC_SHA1"},
{ {0x00, 0xAE},
"TLS_PSK_WITH_AES_128_CBC_SHA256",
"PSK-AES128-CBC-SHA256",
"TLS_PSK_AES_128_CBC_SHA256"},
{ {0x00, 0xA9},
"TLS_PSK_WITH_AES_256_GCM_SHA384",
"PSK-AES256-GCM-SHA384",
"TLS_PSK_AES_256_GCM_SHA384"},
{ {0xC0, 0x8E},
"TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256",
NULL,
"TLS_PSK_CAMELLIA_128_GCM_SHA256"},
{ {0xC0, 0x8F},
"TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384",
NULL,
"TLS_PSK_CAMELLIA_256_GCM_SHA384"},
{ {0x00, 0xA8},
"TLS_PSK_WITH_AES_128_GCM_SHA256",
"PSK-AES128-GCM-SHA256",
"TLS_PSK_AES_128_GCM_SHA256"},
{ {0x00, 0x2C},
"TLS_PSK_WITH_",
NULL,
"TLS_PSK_NULL_SHA1"},
{ {0x00, 0xB0},
"TLS_PSK_WITH_",
NULL,
"TLS_PSK_NULL_SHA256"},
{ {0xC0, 0x94},
"TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256",
NULL,
"TLS_PSK_CAMELLIA_128_CBC_SHA256"},
{ {0xC0, 0x95},
"TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384",
NULL,
"TLS_PSK_CAMELLIA_256_CBC_SHA384"},
{ {0x00, 0xAF},
"TLS_PSK_WITH_AES_256_CBC_SHA384",
"PSK-AES256-CBC-SHA384",
"TLS_PSK_AES_256_CBC_SHA384"},
{ {0x00, 0xB1},
"TLS_PSK_WITH_",
NULL,
"TLS_PSK_NULL_SHA384"},
{ {0x00, 0x92},
"TLS_RSA_PSK_WITH_RC4_128_SHA",
NULL,
"TLS_RSA_PSK_ARCFOUR_128_SHA1"},
{ {0x00, 0x93},
"TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA",
"RSA-PSK-3DES-EDE-CBC-SHA",
"TLS_RSA_PSK_3DES_EDE_CBC_SHA1"},
{ {0x00, 0x94},
"TLS_RSA_PSK_WITH_AES_128_CBC_SHA",
"RSA-PSK-AES128-CBC-SHA",
"TLS_RSA_PSK_AES_128_CBC_SHA1"},
{ {0x00, 0x95},
"TLS_RSA_PSK_WITH_AES_256_CBC_SHA",
"RSA-PSK-AES256-CBC-SHA",
"TLS_RSA_PSK_AES_256_CBC_SHA1"},
{ {0xC0, 0x92},
"TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256",
NULL,
"TLS_RSA_PSK_CAMELLIA_128_GCM_SHA256"},
{ {0xC0, 0x93},
"TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384",
NULL,
"TLS_RSA_PSK_CAMELLIA_256_GCM_SHA384"},
{ {0x00, 0xAC},
"TLS_RSA_PSK_WITH_AES_128_GCM_SHA256",
"RSA-PSK-AES128-GCM-SHA256",
"TLS_RSA_PSK_AES_128_GCM_SHA256"},
{ {0x00, 0xB6},
"TLS_RSA_PSK_WITH_AES_128_CBC_SHA256",
"RSA-PSK-AES128-CBC-SHA256",
"TLS_RSA_PSK_AES_128_CBC_SHA256"},
{ {0x00, 0x2E},
"TLS_RSA_PSK_WITH_NULL_SHA",
NULL,
"TLS_RSA_PSK_NULL_SHA1"},
{ {0x00, 0xB8},
"TLS_RSA_PSK_WITH_",
NULL,
"TLS_RSA_PSK_NULL_SHA256"},
{ {0x00, 0xAD},
"TLS_RSA_PSK_WITH_AES_256_GCM_SHA384",
"RSA-PSK-AES256-GCM-SHA384",
"TLS_RSA_PSK_AES_256_GCM_SHA384"},
{ {0x00, 0xB7},
"TLS_RSA_PSK_WITH_AES_256_CBC_SHA384",
"RSA-PSK-AES256-CBC-SHA384",
"TLS_RSA_PSK_AES_256_CBC_SHA384"},
{ {0x00, 0xB9},
"TLS_RSA_PSK_WITH_",
NULL,
"TLS_RSA_PSK_NULL_SHA384"},
{ {0xC0, 0x98},
"TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256",
NULL,
"TLS_RSA_PSK_CAMELLIA_128_CBC_SHA256"},
{ {0xC0, 0x99},
"TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384",
NULL,
"TLS_RSA_PSK_CAMELLIA_256_CBC_SHA384"},
{ {0x00, 0x8E},
"TLS_DHE_PSK_WITH_RC4_128_SHA",
NULL,
"TLS_DHE_PSK_ARCFOUR_128_SHA1"},
{ {0x00, 0x8F},
"TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA",
"DHE-PSK-3DES-EDE-CBC-SHA",
"TLS_DHE_PSK_3DES_EDE_CBC_SHA1"},
{ {0x00, 0x90},
"TLS_DHE_PSK_WITH_AES_128_CBC_SHA",
"DHE-PSK-AES128-CBC-SHA",
"TLS_DHE_PSK_AES_128_CBC_SHA1"},
{ {0x00, 0x91},
"TLS_DHE_PSK_WITH_AES_256_CBC_SHA",
"DHE-PSK-AES256-CBC-SHA",
"TLS_DHE_PSK_AES_256_CBC_SHA1"},
{ {0x00, 0xB2},
"TLS_DHE_PSK_WITH_AES_128_CBC_SHA256",
"DHE-PSK-AES128-CBC-SHA256",
"TLS_DHE_PSK_AES_128_CBC_SHA256"},
{ {0x00, 0xAA},
"TLS_DHE_PSK_WITH_AES_128_GCM_SHA256",
"DHE-PSK-AES128-GCM-SHA256",
"TLS_DHE_PSK_AES_128_GCM_SHA256"},
{ {0x00, 0x2D},
"TLS_DHE_PSK_WITH_",
NULL,
"TLS_DHE_PSK_NULL_SHA1"},
{ {0x00, 0xB4},
"TLS_DHE_PSK_WITH_",
NULL,
"TLS_DHE_PSK_NULL_SHA256"},
{ {0x00, 0xB5},
"TLS_DHE_PSK_WITH_",
NULL,
"TLS_DHE_PSK_NULL_SHA384"},
{ {0x00, 0xB3},
"TLS_DHE_PSK_WITH_AES_256_CBC_SHA384",
"DHE-PSK-AES256-CBC-SHA384",
"TLS_DHE_PSK_AES_256_CBC_SHA384"},
{ {0x00, 0xAB},
"TLS_DHE_PSK_WITH_AES_256_GCM_SHA384",
"DHE-PSK-AES256-GCM-SHA384",
"TLS_DHE_PSK_AES_256_GCM_SHA384"},
{ {0xC0, 0x96},
"TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256",
NULL,
"TLS_DHE_PSK_CAMELLIA_128_CBC_SHA256"},
{ {0xC0, 0x97},
"TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384",
NULL,
"TLS_DHE_PSK_CAMELLIA_256_CBC_SHA384"},
{ {0xC0, 0x90},
"TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256",
NULL,
"TLS_DHE_PSK_CAMELLIA_128_GCM_SHA256"},
{ {0xC0, 0x91},
"TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384",
NULL,
"TLS_DHE_PSK_CAMELLIA_256_GCM_SHA384"},
{ {0xC0, 0xA4},
"TLS_PSK_WITH_AES_128_CCM",
NULL,
"TLS_PSK_AES_128_CCM"},
{ {0xC0, 0xA5},
"TLS_PSK_WITH_AES_256_CCM",
NULL,
"TLS_PSK_AES_256_CCM"},
{ {0xC0, 0xA6},
"TLS_DHE_PSK_WITH_AES_128_CCM",
NULL,
"TLS_DHE_PSK_AES_128_CCM"},
{ {0xC0, 0xA7},
"TLS_DHE_PSK_WITH_AES_256_CCM",
NULL,
"TLS_DHE_PSK_AES_256_CCM"},
{ {0xC0, 0xA8},
"TLS_PSK_WITH_AES_128_CCM_8",
NULL,
"TLS_PSK_AES_128_CCM_8"},
{ {0xC0, 0xA9},
"TLS_PSK_WITH_AES_256_CCM_8",
NULL,
"TLS_PSK_AES_256_CCM_8"},
{ {0xC0, 0xAA},
"TLS_PSK_DHE_WITH_AES_128_CCM_8",
NULL,
"TLS_DHE_PSK_AES_128_CCM_8"},
{ {0xC0, 0xAB},
"TLS_PSK_DHE_WITH_AES_256_CCM_8",
NULL,
"TLS_DHE_PSK_AES_256_CCM_8"},
{ {0xCC, 0xAD},
"TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256",
"DHE-PSK-CHACHA20-POLY1305",
"TLS_DHE_PSK_CHACHA20_POLY1305"},
{ {0xCC, 0xAC},
"TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256",
"ECDHE-PSK-CHACHA20-POLY1305",
"TLS_ECDHE_PSK_CHACHA20_POLY1305"},
{ {0xCC, 0xAE},
"TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256",
"RSA-PSK-CHACHA20-POLY1305",
"TLS_RSA_PSK_CHACHA20_POLY1305"},
{ {0xCC, 0xAB},
"TLS_PSK_WITH_CHACHA20_POLY1305_SHA256",
"PSK-CHACHA20-POLY1305",
"TLS_PSK_CHACHA20_POLY1305"},
{ {0x00, 0x18},
"TLS_DH_anon_WITH_RC4_128_MD5",
NULL,
"TLS_DH_ANON_ARCFOUR_128_MD5"},
{ {0x00, 0x1B},
"TLS_DH_anon_WITH_3DES_EDE_CBC_SHA",
NULL,
"TLS_DH_ANON_3DES_EDE_CBC_SHA1"},
{ {0x00, 0x34},
"TLS_DH_anon_WITH_AES_128_CBC_SHA",
NULL,
"TLS_DH_ANON_AES_128_CBC_SHA1"},
{ {0x00, 0x3A},
"TLS_DH_anon_WITH_AES_256_CBC_SHA",
NULL,
"TLS_DH_ANON_AES_256_CBC_SHA1"},
{ {0x00, 0xBF},
"TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256",
NULL,
"TLS_DH_ANON_CAMELLIA_128_CBC_SHA256"},
{ {0x00, 0xC5},
"TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256",
NULL,
"TLS_DH_ANON_CAMELLIA_256_CBC_SHA256"},
{ {0x00, 0x46},
"TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA",
NULL,
"TLS_DH_ANON_CAMELLIA_128_CBC_SHA1"},
{ {0x00, 0x89},
"TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA",
NULL,
"TLS_DH_ANON_CAMELLIA_256_CBC_SHA1"},
{ {0x00, 0x6C},
"TLS_DH_anon_WITH_AES_128_CBC_SHA256",
NULL,
"TLS_DH_ANON_AES_128_CBC_SHA256"},
{ {0x00, 0x6D},
"TLS_DH_anon_WITH_AES_256_CBC_SHA256",
NULL,
"TLS_DH_ANON_AES_256_CBC_SHA256"},
{ {0x00, 0xA6},
"TLS_DH_anon_WITH_AES_128_GCM_SHA256",
NULL,
"TLS_DH_ANON_AES_128_GCM_SHA256"},
{ {0x00, 0xA7},
"TLS_DH_anon_WITH_AES_256_GCM_SHA384",
NULL,
"TLS_DH_ANON_AES_256_GCM_SHA384"},
{ {0xC0, 0x84},
"TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256",
NULL,
"TLS_DH_ANON_CAMELLIA_128_GCM_SHA256"},
{ {0xC0, 0x85},
"TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384",
NULL,
"TLS_DH_ANON_CAMELLIA_256_GCM_SHA384"},
{ {0xC0, 0x15},
"TLS_ECDH_anon_WITH_",
NULL,
"TLS_ECDH_ANON_NULL_SHA1"},
{ {0xC0, 0x17},
"TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA",
NULL,
"TLS_ECDH_ANON_3DES_EDE_CBC_SHA1"},
{ {0xC0, 0x18},
"TLS_ECDH_anon_WITH_AES_128_CBC_SHA",
NULL,
"TLS_ECDH_ANON_AES_128_CBC_SHA1"},
{ {0xC0, 0x19},
"TLS_ECDH_anon_WITH_AES_256_CBC_SHA",
NULL,
"TLS_ECDH_ANON_AES_256_CBC_SHA1"},
{ {0xC0, 0x16},
"TLS_ECDH_anon_WITH_RC4_128_SHA",
NULL,
"TLS_ECDH_ANON_ARCFOUR_128_SHA1"},
{ {0xC0, 0x1A},
"TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA",
"SRP-3DES-EDE-CBC-SHA",
"TLS_SRP_SHA_3DES_EDE_CBC_SHA1"},
{ {0xC0, 0x1D},
"TLS_SRP_SHA_WITH_AES_128_CBC_SHA",
"SRP-AES-128-CBC-SHA",
"TLS_SRP_SHA_AES_128_CBC_SHA1"},
{ {0xC0, 0x20},
"TLS_SRP_SHA_WITH_AES_256_CBC_SHA",
"SRP-AES-256-CBC-SHA",
"TLS_SRP_SHA_AES_256_CBC_SHA1"},
{ {0xC0, 0x1C},
"TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA",
NULL,
"TLS_SRP_SHA_DSS_3DES_EDE_CBC_SHA1"},
{ {0xC0, 0x1B},
"TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA",
"SRP-RSA-3DES-EDE-CBC-SHA",
"TLS_SRP_SHA_RSA_3DES_EDE_CBC_SHA1"},
{ {0xC0, 0x1F},
"TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA",
NULL,
"TLS_SRP_SHA_DSS_AES_128_CBC_SHA1"},
{ {0xC0, 0x1E},
"TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA",
"SRP-RSA-AES-128-CBC-SHA",
"TLS_SRP_SHA_RSA_AES_128_CBC_SHA1"},
{ {0xC0, 0x22},
"TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA",
NULL,
"TLS_SRP_SHA_DSS_AES_256_CBC_SHA1"},
{ {0xC0, 0x21},
"TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA",
"SRP-RSA-AES-256-CBC-SHA",
"TLS_SRP_SHA_RSA_AES_256_CBC_SHA1"},
{ {0x00, 0x00},
NULL,
NULL,
NULL}
};
/* free data assigned to the connection */
static void free_gnutls_data(struct st_gnutls_data *data)
{
if (data)
{
if (data->key)
gnutls_privkey_deinit(data->key);
gnutls_pcert_deinit(&data->cert);
free(data);
}
}
/* map the gnutls cipher suite (defined by key exchange algorithm, cipher
and mac algorithm) to the corresponding OpenSSL cipher name */
static const char *openssl_cipher_name(gnutls_kx_algorithm_t kx,
gnutls_cipher_algorithm_t cipher,
gnutls_mac_algorithm_t mac)
{
unsigned int i=0;
const char *name= 0;
unsigned char sid[2];
gnutls_kx_algorithm_t lkx;
gnutls_cipher_algorithm_t lcipher;
gnutls_mac_algorithm_t lmac;
while ((name= gnutls_cipher_suite_info(i++, (unsigned char *)&sid, &lkx, &lcipher, &lmac, NULL)))
{
if (lkx == kx &&
lcipher == cipher &&
lmac == mac)
{
i=0;
while (tls_ciphers[i].iana_name)
{
if (!memcmp(tls_ciphers[i].sid, &sid, 2))
{
if (tls_ciphers[i].openssl_name)
return tls_ciphers[i].openssl_name;
if (tls_ciphers[i].gnutls_name)
return tls_ciphers[i].gnutls_name;
return tls_ciphers[i].iana_name;
}
i++;
}
}
}
return NULL;
}
/* get priority string for a given openssl cipher name */
static char *get_priority(const char *cipher_name, char *priority, size_t len)
{
unsigned int i= 0;
while (tls_ciphers[i].iana_name)
{
if (strcmp(tls_ciphers[i].iana_name, cipher_name) == 0 ||
(tls_ciphers[i].openssl_name &&
strcmp(tls_ciphers[i].openssl_name, cipher_name) == 0) ||
(tls_ciphers[i].gnutls_name &&
strcmp(tls_ciphers[i].gnutls_name, cipher_name) == 0))
{
const char *name;
gnutls_kx_algorithm_t kx;
gnutls_cipher_algorithm_t cipher;
gnutls_mac_algorithm_t mac;
gnutls_protocol_t min_version;
unsigned j= 0;
if (!tls_ciphers[i].gnutls_name)
return NULL;
while ((name= gnutls_cipher_suite_info(j++, NULL, &kx, &cipher,
&mac, &min_version)))
{
if (!strcmp(name, tls_ciphers[i].gnutls_name))
{
snprintf(priority, len - 1, ":+%s:+%s:+%s",
gnutls_cipher_get_name(cipher),
gnutls_mac_get_name(mac),
gnutls_kx_get_name(kx));
return priority;
}
}
return NULL;
}
i++;
}
return NULL;
}
#define MAX_SSL_ERR_LEN 100
static void ma_tls_set_error(MYSQL *mysql, void *ssl, int ssl_errno)
{
char ssl_error[MAX_SSL_ERR_LEN];
const char *ssl_error_reason;
MARIADB_PVIO *pvio= mysql->net.pvio;
if (!ssl_errno)
{
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Unknown SSL error");
return;
}
/* give a more descriptive error message for alerts */
if (ssl_errno == GNUTLS_E_FATAL_ALERT_RECEIVED)
{
gnutls_alert_description_t alert_desc;
const char *alert_name;
alert_desc= gnutls_alert_get((gnutls_session_t)ssl);
alert_name= gnutls_alert_get_name(alert_desc);
snprintf(ssl_error, MAX_SSL_ERR_LEN, "fatal alert received: %s",
alert_name);
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, 0,
ssl_error);
return;
}
if ((ssl_error_reason= gnutls_strerror(ssl_errno)))
{
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, 0,
ssl_error_reason);
return;
}
snprintf(ssl_error, MAX_SSL_ERR_LEN, "SSL errno=%d", ssl_errno);
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
ssl_error);
}
static void ma_tls_get_error(char *errmsg, size_t length, int ssl_errno)
{
const char *ssl_error_reason;
if (!ssl_errno)
{
strncpy(errmsg, "Unknown SSL error", length);
return;
}
if ((ssl_error_reason= gnutls_strerror(ssl_errno)))
{
strncpy(errmsg, ssl_error_reason, length);
return;
}
snprintf(errmsg, length, "SSL errno=%d", ssl_errno);
}
/*
Initializes SSL and allocate global
context SSL_context
SYNOPSIS
my_gnutls_start
mysql connection handle
RETURN VALUES
0 success
1 error
*/
int ma_tls_start(char *errmsg, size_t errmsg_len)
{
int rc= 0;
if (ma_tls_initialized)
return 0;
pthread_mutex_init(&LOCK_gnutls_config,NULL);
pthread_mutex_lock(&LOCK_gnutls_config);
if ((rc= gnutls_global_init()) != GNUTLS_E_SUCCESS)
{
ma_tls_get_error(errmsg, errmsg_len, rc);
goto end;
}
snprintf(tls_library_version, TLS_VERSION_LENGTH - 1, "GnuTLS %s",
gnutls_check_version(NULL));
ma_tls_initialized= TRUE;
end:
pthread_mutex_unlock(&LOCK_gnutls_config);
return rc;
}
/*
Release SSL and free resources
Will be automatically executed by
mysql_server_end() function
SYNOPSIS
my_gnutls_end()
void
RETURN VALUES
void
*/
void ma_tls_end()
{
if (ma_tls_initialized)
{
pthread_mutex_lock(&LOCK_gnutls_config);
if (mariadb_deinitialize_ssl)
gnutls_global_deinit();
ma_tls_initialized= FALSE;
pthread_mutex_unlock(&LOCK_gnutls_config);
pthread_mutex_destroy(&LOCK_gnutls_config);
}
return;
}
static size_t ma_gnutls_get_protocol_version(const char *tls_version_option,
char *priority_string,
size_t prio_len)
{
char tls_versions[128];
tls_versions[0]= 0;
if (!tls_version_option || !tls_version_option[0])
goto end;
if (strstr(tls_version_option, "TLSv1.0"))
strcat(tls_versions, ":+VERS-TLS1.0");
if (strstr(tls_version_option, "TLSv1.1"))
strcat(tls_versions, ":+VERS-TLS1.1");
if (strstr(tls_version_option, "TLSv1.2"))
strcat(tls_versions, ":+VERS-TLS1.2");
#if GNUTLS_VERSION_NUMBER > 0x030605
if (strstr(tls_version_option, "TLSv1.3"))
strcat(tls_versions, ":+VERS-TLS1.3");
#endif
end:
if (tls_versions[0])
snprintf(priority_string, prio_len - 1, "-VERS-TLS-ALL%s:NORMAL", tls_versions);
else
strncpy(priority_string, "NORMAL:+VERS-ALL", prio_len - 1);
return strlen(priority_string);
}
static int ma_gnutls_set_ciphers(gnutls_session_t ssl,
const char *cipher_str,
const char *tls_version)
{
const char *err;
char *token;
#define PRIO_SIZE 1024
char prio[PRIO_SIZE];
ma_gnutls_get_protocol_version(tls_version, prio, PRIO_SIZE);
if (!cipher_str)
return gnutls_priority_set_direct(ssl, prio, &err);
token= strtok((char *)cipher_str, ":");
strcpy(prio, "NONE:+VERS-TLS-ALL:+SIGN-ALL:+COMP-NULL:+CURVE-ALL");
while (token)
{
char priority[1024];
char *p= get_priority(token, priority, 1024);
if (p)
strncat(prio, p, PRIO_SIZE - strlen(prio));
token = strtok(NULL, ":");
}
return gnutls_priority_set_direct(ssl, prio , &err);
}
static int ma_tls_set_certs(MYSQL *mysql,
gnutls_certificate_credentials_t ctx)
{
int ssl_error= 0;
if (mysql->options.ssl_ca)
{
ssl_error= gnutls_certificate_set_x509_trust_file(ctx,
mysql->options.ssl_ca,
GNUTLS_X509_FMT_PEM);
if (ssl_error < 0)
goto error;
}
if (mysql->options.ssl_capath)
{
ssl_error= gnutls_certificate_set_x509_trust_dir(ctx,
mysql->options.ssl_capath,
GNUTLS_X509_FMT_PEM);
if (ssl_error < 0)
goto error;
}
if (mysql->options.extension && mysql->options.extension->ssl_crl)
{
ssl_error= gnutls_certificate_set_x509_crl_file(ctx,
mysql->options.extension->ssl_crl, GNUTLS_X509_FMT_PEM);
if (ssl_error < 0)
goto error;
}
if (!mysql->options.ssl_ca && !mysql->options.ssl_capath)
{
ssl_error= gnutls_certificate_set_x509_system_trust(ctx);
if (ssl_error < 0)
goto error;
}
gnutls_certificate_set_verify_function(ctx,
my_verify_callback);
if (mysql->options.ssl_key || mysql->options.ssl_cert)
{
char *keyfile= mysql->options.ssl_key;
char *certfile= mysql->options.ssl_cert;
if (!certfile)
certfile= keyfile;
else if (!keyfile)
keyfile= certfile;
/* load cert/key into context */
if ((ssl_error= gnutls_certificate_set_x509_key_file2(ctx,
certfile, keyfile, GNUTLS_X509_FMT_PEM,
mysql->options.extension ? mysql->options.extension->tls_pw : NULL, 0)) < 0)
goto error;
}
error:
return ssl_error;
}
void *ma_tls_init(MYSQL *mysql)
{
gnutls_session_t ssl= NULL;
gnutls_certificate_credentials_t ctx;
int ssl_error= 0;
struct st_gnutls_data *data= NULL;
pthread_mutex_lock(&LOCK_gnutls_config);
if (gnutls_certificate_allocate_credentials(&ctx) != GNUTLS_E_SUCCESS)
goto error;
if ((ssl_error= ma_tls_set_certs(mysql, ctx)) < 0)
goto error;
if ((ssl_error = gnutls_init(&ssl, GNUTLS_CLIENT & GNUTLS_NONBLOCK)) < 0)
goto error;
if (!(data= (struct st_gnutls_data *)calloc(1, sizeof(struct st_gnutls_data))))
goto error;
data->mysql= mysql;
gnutls_session_set_ptr(ssl, (void *)data);
ssl_error= ma_gnutls_set_ciphers(ssl, mysql->options.ssl_cipher, mysql->options.extension ? mysql->options.extension->tls_version : NULL);
if (ssl_error < 0)
goto error;
/* we don't load private key and cert by default - if the server requests
a client certificate we will send it via callback function */
if ((ssl_error= gnutls_credentials_set(ssl, GNUTLS_CRD_CERTIFICATE, ctx)) < 0)
goto error;
pthread_mutex_unlock(&LOCK_gnutls_config);
return (void *)ssl;
error:
free_gnutls_data(data);
ma_tls_set_error(mysql, ssl, ssl_error);
gnutls_certificate_free_credentials(ctx);
if (ssl)
gnutls_deinit(ssl);
pthread_mutex_unlock(&LOCK_gnutls_config);
return NULL;
}
#ifdef GNUTLS_EXTERNAL_TRANSPORT
ssize_t ma_tls_push(gnutls_transport_ptr_t ptr, const void* data, size_t len)
{
MARIADB_PVIO *pvio= (MARIADB_PVIO *)ptr;
ssize_t rc= pvio->methods->write(pvio, data, len);
return rc;
}
ssize_t ma_tls_pull(gnutls_transport_ptr_t ptr, void* data, size_t len)
{
MARIADB_PVIO *pvio= (MARIADB_PVIO *)ptr;
ssize_t rc= pvio->methods->read(pvio, data, len);
return rc;
}
static int ma_tls_pull_timeout(gnutls_transport_ptr_t ptr, unsigned int ms)
{
MARIADB_PVIO *pvio= (MARIADB_PVIO *)ptr;
return pvio->methods->wait_io_or_timeout(pvio, 0, ms);
}
#endif
my_bool ma_tls_connect(MARIADB_TLS *ctls)
{
gnutls_session_t ssl = (gnutls_session_t)ctls->ssl;
my_bool blocking;
MYSQL *mysql;
MARIADB_PVIO *pvio;
int ret;
struct st_gnutls_data *data;
data= (struct st_gnutls_data *)gnutls_session_get_ptr(ssl);
mysql= data->mysql;
if (!mysql)
return 1;
pvio= mysql->net.pvio;
/* Set socket to blocking if not already set */
if (!(blocking= pvio->methods->is_blocking(pvio)))
pvio->methods->blocking(pvio, TRUE, 0);
#ifdef GNUTLS_EXTERNAL_TRANSPORT
/* we don't use GnuTLS read/write functions */
gnutls_transport_set_ptr(ssl, pvio);
gnutls_transport_set_push_function(ssl, ma_tls_push);
gnutls_transport_set_pull_function(ssl, ma_tls_pull);
gnutls_transport_set_pull_timeout_function(ssl, ma_tls_pull_timeout);
gnutls_handshake_set_timeout(ssl, pvio->timeout[PVIO_CONNECT_TIMEOUT]);
#else
gnutls_transport_set_int(ssl, mysql_get_socket(mysql));
#endif
do {
ret = gnutls_handshake(ssl);
} while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
if (ret < 0)
{
/* If error message was not set while calling certification callback function,
use default error message (which is not very descriptive */
if (!mysql_errno(mysql))
ma_tls_set_error(mysql, ssl, ret);
ma_tls_close(ctls);
/* restore blocking mode */
if (!blocking)
pvio->methods->blocking(pvio, FALSE, 0);
return 1;
}
ctls->ssl= (void *)ssl;
return 0;
}
ssize_t ma_tls_write_async(MARIADB_PVIO *pvio, const uchar *buffer, size_t length)
{
ssize_t res;
struct mysql_async_context *b= pvio->mysql->options.extension->async_context;
MARIADB_TLS *ctls= pvio->ctls;
for (;;)
{
b->events_to_wait_for= 0;
res= gnutls_record_send((gnutls_session_t)ctls->ssl, (void *)buffer, length);
if (res > 0)
return res;
if (res == GNUTLS_E_AGAIN)
b->events_to_wait_for|= MYSQL_WAIT_WRITE;
else
return res;
if (b->suspend_resume_hook)
(*b->suspend_resume_hook)(TRUE, b->suspend_resume_hook_user_data);
my_context_yield(&b->async_context);
if (b->suspend_resume_hook)
(*b->suspend_resume_hook)(FALSE, b->suspend_resume_hook_user_data);
}
}
ssize_t ma_tls_read_async(MARIADB_PVIO *pvio, const uchar *buffer, size_t length)
{
ssize_t res;
struct mysql_async_context *b= pvio->mysql->options.extension->async_context;
MARIADB_TLS *ctls= pvio->ctls;
for (;;)
{
b->events_to_wait_for= 0;
res= gnutls_record_recv((gnutls_session_t)ctls->ssl, (void *)buffer, length);
if (res > 0)
return res;
if (res == GNUTLS_E_AGAIN)
b->events_to_wait_for|= MYSQL_WAIT_READ;
else
return res;
if (b->suspend_resume_hook)
(*b->suspend_resume_hook)(TRUE, b->suspend_resume_hook_user_data);
my_context_yield(&b->async_context);
if (b->suspend_resume_hook)
(*b->suspend_resume_hook)(FALSE, b->suspend_resume_hook_user_data);
}
}
ssize_t ma_tls_read(MARIADB_TLS *ctls, const uchar* buffer, size_t length)
{
ssize_t rc;
MARIADB_PVIO *pvio= ctls->pvio;
while ((rc= gnutls_record_recv((gnutls_session_t)ctls->ssl, (void *)buffer, length)) <= 0)
{
if (rc != GNUTLS_E_AGAIN && rc != GNUTLS_E_INTERRUPTED)
return rc;
if (pvio->methods->wait_io_or_timeout(pvio, TRUE, pvio->mysql->options.read_timeout) < 1)
return rc;
}
return rc;
}
ssize_t ma_tls_write(MARIADB_TLS *ctls, const uchar* buffer, size_t length)
{
ssize_t rc;
MARIADB_PVIO *pvio= ctls->pvio;
while ((rc= gnutls_record_send((gnutls_session_t)ctls->ssl, (void *)buffer, length)) <= 0)
{
if (rc != GNUTLS_E_AGAIN && rc != GNUTLS_E_INTERRUPTED)
return rc;
if (pvio->methods->wait_io_or_timeout(pvio, TRUE, pvio->mysql->options.write_timeout) < 1)
return rc;
}
return rc;
}
my_bool ma_tls_close(MARIADB_TLS *ctls)
{
if (ctls->ssl)
{
gnutls_certificate_credentials_t ctx;
struct st_gnutls_data *data=
(struct st_gnutls_data *)gnutls_session_get_ptr(ctls->ssl);
/* this would be the correct way, however can't detect afterwards
if the socket is closed or not, so we don't send encrypted
finish alert.
rc= gnutls_bye((gnutls_session_t )ctls->ssl, GNUTLS_SHUT_WR);
*/
free_gnutls_data(data);
gnutls_credentials_get(ctls->ssl, GNUTLS_CRD_CERTIFICATE, (void **)&ctx);
gnutls_certificate_free_keys(ctx);
gnutls_certificate_free_cas(ctx);
gnutls_certificate_free_crls(ctx);
gnutls_certificate_free_ca_names(ctx);
gnutls_certificate_free_credentials(ctx);
gnutls_deinit((gnutls_session_t )ctls->ssl);
ctls->ssl= NULL;
}
return 0;
}
int ma_tls_verify_server_cert(MARIADB_TLS *ctls __attribute__((unused)))
{
/* server verification is already handled before during handshake */
return 0;
}
const char *ma_tls_get_cipher(MARIADB_TLS *ctls)
{
gnutls_kx_algorithm_t kx;
gnutls_cipher_algorithm_t cipher;
gnutls_mac_algorithm_t mac;
if (!ctls || !ctls->ssl)
return NULL;
mac= gnutls_mac_get((gnutls_session_t)ctls->ssl);
cipher= gnutls_cipher_get((gnutls_session_t)ctls->ssl);
kx= gnutls_kx_get((gnutls_session_t)ctls->ssl);
return openssl_cipher_name(kx, cipher, mac);
}
static int my_verify_callback(gnutls_session_t ssl)
{
unsigned int status= 0;
struct st_gnutls_data *data= (struct st_gnutls_data *)gnutls_session_get_ptr(ssl);
MYSQL *mysql;
mysql= data->mysql;
CLEAR_CLIENT_ERROR(mysql);
if ((mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT))
{
const char *hostname= mysql->host;
if (gnutls_certificate_verify_peers3 (ssl, hostname, &status) < 0)
return GNUTLS_E_CERTIFICATE_ERROR;
} else {
if (gnutls_certificate_verify_peers2 (ssl, &status) < 0)
return GNUTLS_E_CERTIFICATE_ERROR;
}
if (status & GNUTLS_CERT_INVALID)
{
gnutls_datum_t out;
int type;
/* accept self signed certificates if we don't have to verify server cert */
if (!(mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT) &&
(status & GNUTLS_CERT_SIGNER_NOT_FOUND))
return 0;
/* gnutls default error message "certificate validation failed" isn't very
descriptive, so we provide more information about the error here */
type= gnutls_certificate_type_get(ssl);
gnutls_certificate_verification_status_print(status, type, &out, 0);
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
ER(CR_SSL_CONNECTION_ERROR), out.data);
gnutls_free(out.data);
return GNUTLS_E_CERTIFICATE_ERROR;
}
return 0;
}
unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, char *fp, unsigned int len)
{
MYSQL *mysql;
size_t fp_len= len;
const gnutls_datum_t *cert_list;
unsigned int cert_list_size;
struct st_gnutls_data *data;
if (!ctls || !ctls->ssl)
return 0;
data= (struct st_gnutls_data *)gnutls_session_get_ptr(ctls->ssl);
mysql= (MYSQL *)data->mysql;
cert_list = gnutls_certificate_get_peers (ctls->ssl, &cert_list_size);
if (cert_list == NULL)
{
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
ER(CR_SSL_CONNECTION_ERROR),
"Unable to get server certificate");
return 0;
}
if (gnutls_fingerprint(GNUTLS_DIG_SHA1, &cert_list[0], fp, &fp_len) == 0)
return fp_len;
else
{
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
ER(CR_SSL_CONNECTION_ERROR),
"Finger print buffer too small");
return 0;
}
}
int ma_tls_get_protocol_version(MARIADB_TLS *ctls)
{
if (!ctls || !ctls->ssl)
return 1;
return gnutls_protocol_get_version(ctls->ssl) - 1;
}
#endif /* HAVE_GNUTLS */