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

SSL fixes:

- added MARIADB_OPT_SSL_CIPHER_STRENGTH (value uint) for Schannel
- fixed mutes in all ssl variants
This commit is contained in:
Georg Richter
2016-02-16 13:04:16 +01:00
parent 448b68023c
commit 509b948e7d
12 changed files with 264 additions and 199 deletions

View File

@@ -53,6 +53,7 @@ struct st_mysql_options_extension {
char *ssl_fp_list; /* white list of finger prints */
char *ssl_pw; /* password for encrypted certificates */
char *url; /* for connection handler we need to save URL for reconnect */
unsigned int ssl_cipher_strength;
my_bool read_only;
char *connection_handler;
HASH userdata;

View File

@@ -221,6 +221,7 @@ extern unsigned int mariadb_deinitialize_ssl;
MARIADB_OPT_CONNECTION_READ_ONLY,
MYSQL_OPT_CONNECT_ATTRS, /* for mysql_get_optionv */
MARIADB_OPT_USERDATA,
MARIADB_OPT_SSL_CIPHER_STRENGTH,
MARIADB_OPT_CONNECTION_HANDLER
};

View File

@@ -2930,6 +2930,9 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...)
my_free(mysql->options.bind_address);
mysql->options.bind_address= my_strdup(arg1, MYF(MY_WME));
break;
case MARIADB_OPT_SSL_CIPHER_STRENGTH:
OPT_SET_EXTENDED_VALUE_INT(&mysql->options, ssl_cipher_strength, *((unsigned int *)arg1));
break;
case MARIADB_OPT_SSL_FP:
OPT_SET_EXTENDED_VALUE_STR(&mysql->options, ssl_fp, (char *)arg1);
break;
@@ -3108,6 +3111,9 @@ mysql_get_optionv(MYSQL *mysql, enum mysql_option option, void *arg, ...)
case MYSQL_OPT_BIND:
*((char **)arg)= mysql->options.bind_address;
break;
case MARIADB_OPT_SSL_CIPHER_STRENGTH:
*((unsigned int *)arg) = mysql->options.extension ? mysql->options.extension->ssl_cipher_strength : 0;
break;
case MARIADB_OPT_SSL_FP:
*((char **)arg)= mysql->options.extension ? mysql->options.extension->ssl_fp : NULL;
break;

View File

@@ -521,7 +521,8 @@ my_bool ma_pvio_start_ssl(MARIADB_PVIO *pvio)
return 1;
if (pvio->mysql->options.extension &&
(pvio->mysql->options.extension->ssl_fp || pvio->mysql->options.extension->ssl_fp_list))
(pvio->mysql->options.extension->ssl_fp && pvio->mysql->options.extension->ssl_fp[0]) ||
(pvio->mysql->options.extension->ssl_fp_list && pvio->mysql->options.extension->ssl_fp_list[0]))
{
if (ma_pvio_ssl_check_fp(pvio->cssl,

View File

@@ -140,6 +140,7 @@ my_bool ma_pvio_ssl_check_fp(MARIADB_SSL *cssl, const char *fp, const char *fp_l
unsigned int cert_fp_len= 64;
unsigned char cert_fp[64];
my_bool rc=1;
MYSQL *mysql= cssl->pvio->mysql;
if ((cert_fp_len= ma_ssl_get_finger_print(cssl, cert_fp, cert_fp_len)) < 1)
goto end;
@@ -147,20 +148,15 @@ my_bool ma_pvio_ssl_check_fp(MARIADB_SSL *cssl, const char *fp, const char *fp_l
rc= ma_pvio_ssl_compare_fp(cert_fp, cert_fp_len, (char *)fp, (unsigned int)strlen(fp));
else if (fp_list)
{
FILE *fp;
MA_FILE *fp;
char buff[255];
if (!(fp = fopen(fp_list, "r")))
if (!(fp = ma_open(fp_list, "r", mysql)))
{
/*
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
ER(CR_SSL_CONNECTION_ERROR),
"Can't open finger print list");
*/
goto end;
return 1;
}
while (fgets(buff, sizeof(buff)-1, fp))
while (ma_gets(buff, sizeof(buff)-1, fp))
{
/* remove trailing new line character */
char *pos= strchr(buff, '\r');
@@ -172,18 +168,23 @@ my_bool ma_pvio_ssl_check_fp(MARIADB_SSL *cssl, const char *fp, const char *fp_l
if (!ma_pvio_ssl_compare_fp(cert_fp, cert_fp_len, buff, (unsigned int)strlen(buff)))
{
/* finger print is valid: close file and exit */
fclose(fp);
ma_close(fp);
rc= 0;
goto end;
}
}
/* No finger print matched - close file and return error */
fclose(fp);
ma_close(fp);
}
end:
if (rc)
{
my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
ER(CR_SSL_CONNECTION_ERROR),
"Fingerprint verification of server certificate failed");
}
return rc;
}
#endif /* HAVE_SSL */

View File

@@ -97,20 +97,20 @@ int ma_ssl_start(char *errmsg, size_t errmsg_len)
{
int rc= 0;
if (ma_ssl_initialized)
return 0;
pthread_mutex_init(&LOCK_gnutls_config,MY_MUTEX_INIT_FAST);
pthread_mutex_lock(&LOCK_gnutls_config);
if (!ma_ssl_initialized)
if ((rc= gnutls_global_init()) != GNUTLS_E_SUCCESS)
{
if ((rc= gnutls_global_init()) != GNUTLS_E_SUCCESS)
{
ma_ssl_get_error(errmsg, errmsg_len, rc);
goto end;
}
ma_ssl_initialized= TRUE;
ma_ssl_get_error(errmsg, errmsg_len, rc);
goto end;
}
/* Allocate a global context for credentials */
rc= gnutls_certificate_allocate_credentials(&GNUTLS_xcred);
ma_ssl_initialized= TRUE;
end:
pthread_mutex_unlock(&LOCK_gnutls_config);
return rc;
@@ -130,9 +130,9 @@ end:
*/
void ma_ssl_end()
{
pthread_mutex_lock(&LOCK_gnutls_config);
if (ma_ssl_initialized)
{
pthread_mutex_lock(&LOCK_gnutls_config);
gnutls_certificate_free_keys(GNUTLS_xcred);
gnutls_certificate_free_cas(GNUTLS_xcred);
gnutls_certificate_free_crls(GNUTLS_xcred);
@@ -141,9 +141,9 @@ void ma_ssl_end()
if (mariadb_deinitialize_ssl)
gnutls_global_deinit();
ma_ssl_initialized= FALSE;
pthread_mutex_unlock(&LOCK_gnutls_config);
pthread_mutex_destroy(&LOCK_gnutls_config);
}
pthread_mutex_unlock(&LOCK_gnutls_config);
pthread_mutex_destroy(&LOCK_gnutls_config);
return;
}

View File

@@ -387,7 +387,7 @@ end:
SECURITY_STATUS ma_schannel_handshake_loop(MARIADB_PVIO *pvio, my_bool InitialRead, SecBuffer *pExtraData)
{
SecBufferDesc OutBuffer, InBuffer;
SecBuffer InBuffers[2], OutBuffers[1];
SecBuffer InBuffers[2], OutBuffers;
DWORD dwSSPIFlags, dwSSPIOutFlags, cbData, cbIoBuffer;
TimeStamp tsExpiry;
SECURITY_STATUS rc;
@@ -457,12 +457,12 @@ SECURITY_STATUS ma_schannel_handshake_loop(MARIADB_PVIO *pvio, my_bool InitialRe
/* output buffer */
OutBuffers[0].pvBuffer = NULL;
OutBuffers[0].BufferType= SECBUFFER_TOKEN;
OutBuffers[0].cbBuffer = 0;
OutBuffers.pvBuffer = NULL;
OutBuffers.BufferType= SECBUFFER_TOKEN;
OutBuffers.cbBuffer = 0;
OutBuffer.cBuffers = 1;
OutBuffer.pBuffers = OutBuffers;
OutBuffer.pBuffers = &OutBuffers;
OutBuffer.ulVersion = SECBUFFER_VERSION;
@@ -484,19 +484,19 @@ SECURITY_STATUS ma_schannel_handshake_loop(MARIADB_PVIO *pvio, my_bool InitialRe
rc == SEC_I_CONTINUE_NEEDED ||
FAILED(rc) && (dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR))
{
if(OutBuffers[0].cbBuffer && OutBuffers[0].pvBuffer)
if(OutBuffers.cbBuffer && OutBuffers.pvBuffer)
{
cbData= (DWORD)pvio->methods->write(pvio, (uchar *)OutBuffers[0].pvBuffer, (size_t)OutBuffers[0].cbBuffer);
cbData= (DWORD)pvio->methods->write(pvio, (uchar *)OutBuffers.pvBuffer, (size_t)OutBuffers.cbBuffer);
if(cbData == SOCKET_ERROR || cbData == 0)
{
FreeContextBuffer(OutBuffers[0].pvBuffer);
FreeContextBuffer(OutBuffers.pvBuffer);
DeleteSecurityContext(&sctx->ctxt);
return SEC_E_INTERNAL_ERROR;
}
/* Free output context buffer */
FreeContextBuffer(OutBuffers[0].pvBuffer);
OutBuffers[0].pvBuffer = NULL;
FreeContextBuffer(OutBuffers.pvBuffer);
OutBuffers.pvBuffer = NULL;
}
}
@@ -589,7 +589,7 @@ SECURITY_STATUS ma_schannel_client_handshake(MARIADB_SSL *cssl)
ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM;
SecBufferDesc BufferOut;
SecBuffer BuffersOut[1];
SecBuffer BuffersOut;
if (!cssl || !cssl->pvio)
return 1;
@@ -598,13 +598,13 @@ SECURITY_STATUS ma_schannel_client_handshake(MARIADB_SSL *cssl)
sctx= (SC_CTX *)cssl->ssl;
/* Initialie securifty context */
BuffersOut[0].BufferType= SECBUFFER_TOKEN;
BuffersOut[0].cbBuffer= 0;
BuffersOut[0].pvBuffer= NULL;
BuffersOut.BufferType= SECBUFFER_TOKEN;
BuffersOut.cbBuffer= 0;
BuffersOut.pvBuffer= NULL;
BufferOut.cBuffers= 1;
BufferOut.pBuffers= BuffersOut;
BufferOut.pBuffers= &BuffersOut;
BufferOut.ulVersion= SECBUFFER_VERSION;
sRet = InitializeSecurityContext(&sctx->CredHdl,
@@ -627,9 +627,9 @@ SECURITY_STATUS ma_schannel_client_handshake(MARIADB_SSL *cssl)
}
/* send client hello packaet */
if(BuffersOut[0].cbBuffer != 0 && BuffersOut[0].pvBuffer != NULL)
if(BuffersOut.cbBuffer != 0 && BuffersOut.pvBuffer != NULL)
{
r= (DWORD)pvio->methods->write(pvio, (uchar *)BuffersOut[0].pvBuffer, (size_t)BuffersOut[0].cbBuffer);
r= (DWORD)pvio->methods->write(pvio, (uchar *)BuffersOut.pvBuffer, (size_t)BuffersOut.cbBuffer);
if (r <= 0)
{
sRet= SEC_E_INTERNAL_ERROR;
@@ -654,7 +654,7 @@ SECURITY_STATUS ma_schannel_client_handshake(MARIADB_SSL *cssl)
end:
LocalFree(sctx->IoBuffer);
sctx->IoBufferSize= 0;
FreeContextBuffer(BuffersOut[0].pvBuffer);
FreeContextBuffer(BuffersOut.pvBuffer);
DeleteSecurityContext(&sctx->ctxt);
return sRet;
}
@@ -782,6 +782,9 @@ my_bool ma_schannel_verify_certs(SC_CTX *sctx, DWORD dwCertFlags)
DWORD flags;
MARIADB_PVIO *pvio= sctx->mysql->net.pvio;
PCCERT_CONTEXT pServerCert= NULL;
PCERT_CONTEXT ca_CTX = NULL;
PCRL_CONTEXT crl_CTX = NULL;
my_bool is_Ok = 0;
if ((sRet= QueryContextAttributes(&sctx->ctxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&pServerCert)) != SEC_E_OK)
{
@@ -789,16 +792,22 @@ my_bool ma_schannel_verify_certs(SC_CTX *sctx, DWORD dwCertFlags)
return 0;
}
flags= CERT_STORE_SIGNATURE_FLAG |
CERT_STORE_TIME_VALIDITY_FLAG;
if (sctx->client_ca_ctx)
if (ca_Check)
{
if (!(sRet= CertVerifySubjectCertificateContext(pServerCert,
sctx->client_ca_ctx,
&flags)))
flags = CERT_STORE_SIGNATURE_FLAG |
CERT_STORE_TIME_VALIDITY_FLAG;
while ((ca_CTX = CertFindCertificateInStore(ca_CertStore, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
0, CERT_FIND_ANY, 0, ca_CTX)) && !is_Ok)
{
if (sRet = CertVerifySubjectCertificateContext(pServerCert, ca_CTX, &flags))
is_Ok = 1;
}
if (ca_CTX)
CertFreeCertificateContext(ca_CTX);
if (!is_Ok)
{
ma_schannel_set_win_error(pvio);
return 0;
@@ -819,18 +828,23 @@ my_bool ma_schannel_verify_certs(SC_CTX *sctx, DWORD dwCertFlags)
}
/* Check if none of the certificates in the certificate chain have been revoked. */
if (sctx->client_crl_ctx)
if (crl_Check)
{
PCRL_INFO Info[1];
Info[0]= sctx->client_crl_ctx->pCrlInfo;
if (!(CertVerifyCRLRevocation(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
pServerCert->pCertInfo,
1, Info)) )
while ((crl_CTX = CertEnumCRLsInStore(crl_CertStore, crl_CTX)))
{
pvio->set_error(pvio->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "CRL Revocation failed");
return 0;
PCRL_INFO Info[1];
Info[0] = crl_CTX->pCrlInfo;
if (!(CertVerifyCRLRevocation(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
pServerCert->pCertInfo,
1, Info)))
{
CertFreeCRLContext(crl_CTX);
pvio->set_error(pvio->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "CRL Revocation failed");
return 0;
}
}
CertFreeCRLContext(crl_CTX);
}
return 1;
}

View File

@@ -56,19 +56,10 @@ typedef void VOID;
struct st_schannel {
HCERTSTORE cert_store;
CERT_CONTEXT *client_cert_ctx;
CERT_CONTEXT *client_ca_ctx;
CRL_CONTEXT *client_crl_ctx;
CredHandle CredHdl;
my_bool FreeCredHdl;
PUCHAR IoBuffer;
DWORD IoBufferSize;
/* PUCHAR EncryptBuffer;
DWORD EncryptBufferSize;
DWORD EncryptBufferLength;
PUCHAR DecryptBuffer;
DWORD DecryptBufferSize;
DWORD DecryptBufferLength;
uchar thumbprint[21]; */
SecPkgContext_StreamSizes Sizes;
CtxtHandle ctxt;
@@ -77,6 +68,9 @@ struct st_schannel {
typedef struct st_schannel SC_CTX;
extern HCERTSTORE ca_CertStore, crl_CertStore;
extern my_bool ca_Check, crl_Check;
CERT_CONTEXT *ma_schannel_create_cert_context(MARIADB_PVIO *pvio, const char *pem_file);
SECURITY_STATUS ma_schannel_client_handshake(MARIADB_SSL *cssl);
SECURITY_STATUS ma_schannel_handshake_loop(MARIADB_PVIO *pvio, my_bool InitialRead, SecBuffer *pExtraData);

View File

@@ -159,37 +159,37 @@ static int ssl_thread_init()
int ma_ssl_start(char *errmsg, size_t errmsg_len)
{
int rc= 1;
if (ma_ssl_initialized)
return 0;
/* lock mutex to prevent multiple initialization */
pthread_mutex_init(&LOCK_openssl_config,MY_MUTEX_INIT_FAST);
pthread_mutex_lock(&LOCK_openssl_config);
if (!ma_ssl_initialized)
if (ssl_thread_init())
{
if (ssl_thread_init())
{
strncpy(errmsg, "Not enough memory", errmsg_len);
goto end;
}
SSL_library_init();
strncpy(errmsg, "Not enough memory", errmsg_len);
goto end;
}
SSL_library_init();
#if SSLEAY_VERSION_NUMBER >= 0x00907000L
OPENSSL_config(NULL);
OPENSSL_config(NULL);
#endif
/* load errors */
SSL_load_error_strings();
/* digests and ciphers */
OpenSSL_add_all_algorithms();
/* load errors */
SSL_load_error_strings();
/* digests and ciphers */
OpenSSL_add_all_algorithms();
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
if (!(SSL_context= SSL_CTX_new(TLS_client_method())))
if (!(SSL_context= SSL_CTX_new(TLS_client_method())))
#else
if (!(SSL_context= SSL_CTX_new(SSLv23_client_method())))
if (!(SSL_context= SSL_CTX_new(SSLv23_client_method())))
#endif
{
ma_ssl_get_error(errmsg, errmsg_len);
goto end;
}
rc= 0;
ma_ssl_initialized= TRUE;
{
ma_ssl_get_error(errmsg, errmsg_len);
goto end;
}
rc= 0;
ma_ssl_initialized= TRUE;
end:
pthread_mutex_unlock(&LOCK_openssl_config);
return rc;
@@ -209,10 +209,10 @@ end:
*/
void ma_ssl_end()
{
pthread_mutex_lock(&LOCK_openssl_config);
if (ma_ssl_initialized)
{
int i;
pthread_mutex_lock(&LOCK_openssl_config);
CRYPTO_set_locking_callback(NULL);
CRYPTO_set_id_callback(NULL);
@@ -238,9 +238,9 @@ void ma_ssl_end()
sk_SSL_COMP_free(SSL_COMP_get_compression_methods());
}
ma_ssl_initialized= FALSE;
pthread_mutex_unlock(&LOCK_openssl_config);
pthread_mutex_destroy(&LOCK_openssl_config);
}
pthread_mutex_unlock(&LOCK_openssl_config);
pthread_mutex_destroy(&LOCK_openssl_config);
return;
}

View File

@@ -34,61 +34,57 @@ struct st_cipher_suite {
CHAR *cipher;
};
const struct st_cipher_suite valid_ciphers[] =
{
{ CALG_3DES, "CALG_3DES" },
{ CALG_3DES_112, "CALG_3DES_112" },
{ CALG_AES, "CALG_AES" },
{ CALG_AES_128, "CALG_AES_128" },
{ CALG_AES_192, "CALG_AES_192" },
{ CALG_AES_256, "CALG_AES_256" },
{ CALG_AGREEDKEY_ANY, "CALG_AGREEDKEY_ANY" },
{ CALG_CYLINK_MEK, "CALG_CYLINK_MEK" },
{ CALG_DES, "CALG_DES" },
{ CALG_DESX, "CALG_DESX" },
{ CALG_DH_EPHEM, "CALG_DH_EPHEM" },
{ CALG_DH_SF, "CALG_DH_SF" },
{ CALG_DSS_SIGN, "CALG_DSS_SIGN" },
{ CALG_ECDH, "CALG_ECDH" },
{ CALG_ECDSA, "CALG_ECDSA" },
{ CALG_ECMQV, "CALG_ECMQV" },
{ CALG_HASH_REPLACE_OWF, "CALG_HASH_REPLACE_OWF" },
{ CALG_HUGHES_MD5, "CALG_HUGHES_MD5" },
{ CALG_HMAC, "CALG_HMAC" },
{ CALG_KEA_KEYX, "CALG_KEA_KEYX" },
{ CALG_MAC, "CALG_MAC" },
{ CALG_MD2, "CALG_MD2" },
{ CALG_MD4, "CALG_MD4" },
{ CALG_MD4, "CALG_MD5" },
{ CALG_NO_SIGN, "CALG_NO_SIGN" },
{ CALG_OID_INFO_CNG_ONLY, "CALG_OID_INFO_CNG_ONLY" },
{ CALG_OID_INFO_PARAMETERS, "CALG_OID_INFO_PARAMETERS" },
{ CALG_RC2, "CALG_RC2" },
{ CALG_RC4, "CALG_RC4" },
{ CALG_RC5, "CALG_RC5" },
{ CALG_RSA_KEYX, "CALG_RSA_KEYX" },
{ CALG_RSA_SIGN, "CALG_RSA_SIGN" },
{ CALG_SHA, "CALG_SHA" },
{ CALG_SHA1, "CALG_SHA1" },
{ CALG_SHA_256, "CALG_SHA_256" },
{ CALG_SHA_384, "CALG_SHA_384" },
{ CALG_SHA_512, "CALG_SHA_512" },
{ 0, NULL }
};
#define MAX_ALG_ID 50
void ma_schannel_set_sec_error(MARIADB_PVIO *pvio, DWORD ErrorNo);
void ma_schannel_set_win_error(MYSQL *mysql);
const struct st_cipher_suite sc_ciphers[]=
{
{CALG_3DES, "CALG_3DES"},
{CALG_3DES_112, "CALG_3DES_112"},
{CALG_AES, "CALG_AES"},
{CALG_AES_128, "CALG_AES_128"},
{CALG_AES_192, "CALG_AES_192"},
{CALG_AES_256, "CALG_AES_256"},
{CALG_AGREEDKEY_ANY, "CALG_AGREEDKEY_ANY"},
{CALG_CYLINK_MEK, "CALG_CYLINK_MEK"},
{CALG_DES, "CALG_DES"},
{CALG_DESX, "CALG_DESX"},
{CALG_DH_EPHEM, "CALG_DH_EPHEM"},
{CALG_DH_SF, "CALG_DH_SF"},
{CALG_DSS_SIGN, "CALG_DSS_SIGN"},
{CALG_ECDH, "CALG_ECDH"},
{CALG_ECDSA, "CALG_ECDSA"},
{CALG_ECMQV, "CALG_ECMQV"},
{CALG_HASH_REPLACE_OWF, "CALG_HASH_REPLACE_OWF"},
{CALG_HUGHES_MD5, "CALG_HUGHES_MD5"},
{CALG_HMAC, "CALG_HMAC"},
{CALG_KEA_KEYX, "CALG_KEA_KEYX"},
{CALG_MAC, "CALG_MAC"},
{CALG_MD2, "CALG_MD2"},
{CALG_MD4, "CALG_MD4"},
{CALG_MD4, "CALG_MD5"},
{CALG_NO_SIGN, "CALG_NO_SIGN"},
{CALG_OID_INFO_CNG_ONLY, "CALG_OID_INFO_CNG_ONLY"},
{CALG_OID_INFO_PARAMETERS, "CALG_OID_INFO_PARAMETERS"},
{CALG_PCT1_MASTER, "CALG_PCT1_MASTER"},
{CALG_RC2, "CALG_RC2"},
{CALG_RC4, "CALG_RC4"},
{CALG_RC5, "CALG_RC5"},
{CALG_RSA_KEYX, "CALG_RSA_KEYX"},
{CALG_RSA_SIGN, "CALG_RSA_SIGN"},
{CALG_SCHANNEL_MAC_KEY, "CALG_SCHANNEL_MAC_KEY"},
{CALG_SCHANNEL_MASTER_HASH, "CALG_SCHANNEL_MASTER_HASH"},
{CALG_SEAL, "CALG_SEAL"},
{CALG_SHA, "CALG_SHA"},
{CALG_SHA1, "CALG_SHA1"},
{CALG_SHA_256, "CALG_SHA_256"},
{CALG_SHA_384, "CALG_SHA_384"},
{CALG_SHA_512, "CALG_SHA_512"},
{CALG_SKIPJACK, "CALG_SKIPJACK"},
{CALG_SSL2_MASTER, "CALG_SSL2_MASTER"},
{CALG_SSL3_MASTER, "CALG_SSL3_MASTER"},
{CALG_SSL3_SHAMD5, "CALG_SSL3_SHAMD5"},
{CALG_TEK, "CALG_TEK"},
{CALG_TLS1_MASTER, "CALG_TLS1_MASTER"},
{CALG_TLS1PRF, "CALG_TLS1PRF"},
{0, NULL}
};
HCERTSTORE ca_CertStore= NULL,
crl_CertStore= NULL;
my_bool ca_Check = 0, crl_Check = 0;
static int ssl_thread_init()
{
@@ -113,7 +109,17 @@ int ma_ssl_start(char *errmsg, size_t errmsg_len)
{
pthread_mutex_init(&LOCK_schannel_config,MY_MUTEX_INIT_FAST);
pthread_mutex_lock(&LOCK_schannel_config);
ma_ssl_initialized= TRUE;
if (!ca_CertStore)
{
if (!(ca_CertStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, 0, NULL)) ||
!(crl_CertStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, 0, NULL)))
{
snprintf(errmsg, errmsg_len, "Can't open in-memory certstore. Error=%d", GetLastError());
return 1;
}
}
ma_ssl_initialized = TRUE;
pthread_mutex_unlock(&LOCK_schannel_config);
}
return 0;
@@ -133,14 +139,23 @@ int ma_ssl_start(char *errmsg, size_t errmsg_len)
*/
void ma_ssl_end()
{
pthread_mutex_lock(&LOCK_schannel_config);
if (ma_ssl_initialized)
{
pthread_mutex_lock(&LOCK_schannel_config);
if (ca_CertStore)
{
CertCloseStore(ca_CertStore, 0);
ca_CertStore = 0;
}
if (crl_CertStore)
{
CertCloseStore(crl_CertStore, 0);
crl_CertStore = 0;
}
ma_ssl_initialized= FALSE;
pthread_mutex_unlock(&LOCK_schannel_config);
pthread_mutex_destroy(&LOCK_schannel_config);
}
pthread_mutex_unlock(&LOCK_schannel_config);
pthread_mutex_destroy(&LOCK_schannel_config);
return;
}
@@ -151,32 +166,26 @@ static int ma_ssl_set_client_certs(MARIADB_SSL *cssl)
char *certfile= mysql->options.ssl_cert,
*keyfile= mysql->options.ssl_key,
*cafile= mysql->options.ssl_ca;
PCERT_CONTEXT ca_ctx= NULL;
PCRL_CONTEXT crl_ctx = NULL;
SC_CTX *sctx= (SC_CTX *)cssl->ssl;
MARIADB_PVIO *pvio= cssl->pvio;
if (cafile)
{
HCERTSTORE myCS= NULL;
if (!(sctx->client_ca_ctx = ma_schannel_create_cert_context(pvio, cafile)))
if (!(ca_ctx = ma_schannel_create_cert_context(pvio, cafile)))
goto end;
/* For X509 authentication we need to add ca certificate to local MY store.
Schannel doesn't provide a callback to send ca to server during handshake */
if ((myCS= CertOpenStore(CERT_STORE_PROV_SYSTEM,
0, //X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
0,
CERT_SYSTEM_STORE_CURRENT_USER,
L"CA")))
/* Add ca to in-memory certificate store */
if (CertAddCertificateContextToStore(ca_CertStore, ca_ctx, CERT_STORE_ADD_NEWER, NULL) != TRUE &&
GetLastError() != CRYPT_E_EXISTS)
{
CertAddCertificateContextToStore(myCS, sctx->client_ca_ctx, CERT_STORE_ADD_NEWER, NULL);
CertCloseStore(myCS, 0);
}
else {
ma_schannel_set_win_error(sctx->mysql);
goto end;
}
ca_Check= 0;
CertFreeCertificateContext(ca_ctx);
}
if (!certfile && keyfile)
@@ -194,20 +203,28 @@ static int ma_ssl_set_client_certs(MARIADB_SSL *cssl)
if (mysql->options.extension && mysql->options.extension->ssl_crl)
{
if (!(sctx->client_crl_ctx= (CRL_CONTEXT *)ma_schannel_create_crl_context(pvio, mysql->options.extension->ssl_crl)))
if (!(crl_ctx= (CRL_CONTEXT *)ma_schannel_create_crl_context(pvio, mysql->options.extension->ssl_crl)))
goto end;
/* Add ca to in-memory certificate store */
if (CertAddCRLContextToStore(crl_CertStore, crl_ctx, CERT_STORE_ADD_NEWER, NULL) != TRUE &&
GetLastError() != CRYPT_E_EXISTS)
{
ma_schannel_set_win_error(sctx->mysql);
goto end;
}
crl_Check = 1;
CertFreeCertificateContext(ca_ctx);
}
return 0;
end:
if (sctx->client_ca_ctx)
CertFreeCertificateContext(sctx->client_ca_ctx);
if (ca_ctx)
CertFreeCertificateContext(ca_ctx);
if (sctx->client_cert_ctx)
CertFreeCertificateContext(sctx->client_cert_ctx);
if (sctx->client_crl_ctx)
CertFreeCRLContext(sctx->client_crl_ctx);
sctx->client_ca_ctx= sctx->client_cert_ctx= NULL;
sctx->client_crl_ctx= NULL;
if (crl_ctx)
CertFreeCRLContext(crl_ctx);
sctx->client_cert_ctx= NULL;
return 1;
}
/* }}} */
@@ -243,7 +260,7 @@ my_bool ma_ssl_connect(MARIADB_SSL *cssl)
SECURITY_STATUS sRet;
PCCERT_CONTEXT pRemoteCertContext = NULL,
pLocalCertContext= NULL;
ALG_ID AlgId[2]= {0, 0};
ALG_ID AlgId[MAX_ALG_ID]= {0};
if (!cssl || !cssl->pvio)
return 1;;
@@ -260,31 +277,42 @@ my_bool ma_ssl_connect(MARIADB_SSL *cssl)
if (ma_ssl_set_client_certs(cssl))
goto end;
ZeroMemory(&Cred, sizeof(SCHANNEL_CRED));
/* Set cipher */
if (mysql->options.ssl_cipher)
{
DWORD i= 0;
while (sc_ciphers[i].cipher) {
if (!strcmp(sc_ciphers[i].cipher, mysql->options.ssl_cipher))
WORD validTokens = 0;
char *token = strtok(mysql->options.ssl_cipher, ":");
while (token)
{
struct st_cipher_suite *valid;
for (valid = valid_ciphers; valid && valid->aid; valid++)
{
AlgId[0]= sc_ciphers[i].aid;
break;
if (!strcmp(token, valid->cipher))
{
AlgId[validTokens++] = valid->aid;
break;
}
}
token = strtok(NULL, ":");
}
Cred.palgSupportedAlgs= (ALG_ID *)&AlgId;
}
ZeroMemory(&Cred, sizeof(SCHANNEL_CRED));
Cred.palgSupportedAlgs = (ALG_ID *)&AlgId;
Cred.dwVersion= SCHANNEL_CRED_VERSION;
Cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK | SCH_SEND_ROOT_CERT |
SCH_CRED_NO_DEFAULT_CREDS | SCH_CRED_MANUAL_CRED_VALIDATION;
if (mysql->options.extension)
Cred.dwMinimumCipherStrength = MAX(128, mysql->options.extension->ssl_cipher_strength);
else
Cred.dwMinimumCipherStrength = 128;
Cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK | SCH_SEND_ROOT_CERT |
SCH_CRED_NO_DEFAULT_CREDS | SCH_CRED_MANUAL_CRED_VALIDATION;
if (sctx->client_cert_ctx)
{
Cred.cCreds = 1;
Cred.paCred = &sctx->client_cert_ctx;
}
Cred.grbitEnabledProtocols= SP_PROT_TLS1_1PLUS;
Cred.grbitEnabledProtocols = SP_PROT_TLS1_0 | SP_PROT_TLS1_1 | SP_PROT_TLS1_2;
if ((sRet= AcquireCredentialsHandleA(NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND,
NULL, &Cred, NULL, NULL, &sctx->CredHdl, NULL)) != SEC_E_OK)
@@ -315,15 +343,9 @@ end:
if (rc && sctx->IoBufferSize)
LocalFree(sctx->IoBuffer);
sctx->IoBufferSize= 0;
if (sctx->client_ca_ctx)
CertFreeCertificateContext(sctx->client_ca_ctx);
if (sctx->client_cert_ctx)
CertFreeCertificateContext(sctx->client_cert_ctx);
if (sctx->client_crl_ctx)
CertFreeCRLContext(sctx->client_crl_ctx);
sctx->client_ca_ctx= 0;
sctx->client_cert_ctx= 0;
sctx->client_crl_ctx= 0;
return 1;
}
@@ -363,12 +385,8 @@ my_bool ma_ssl_close(MARIADB_SSL *cssl)
{
if (sctx->IoBufferSize)
LocalFree(sctx->IoBuffer);
if (sctx->client_ca_ctx)
CertFreeCertificateContext(sctx->client_ca_ctx);
if (sctx->client_cert_ctx)
CertFreeCertificateContext(sctx->client_cert_ctx);
if (sctx->client_crl_ctx)
CertFreeCRLContext(sctx->client_crl_ctx);
FreeCredentialHandle(&sctx->CredHdl);
DeleteSecurityContext(&sctx->ctxt);
}
@@ -458,10 +476,10 @@ const char *ma_ssl_get_cipher(MARIADB_SSL *cssl)
if (sRet != SEC_E_OK)
return NULL;
while (sc_ciphers[i].cipher)
while (valid_ciphers[i].cipher)
{
if (sc_ciphers[i].aid == cinfo.aiCipher)
return sc_ciphers[i].cipher;
if (valid_ciphers[i].aid == cinfo.aiCipher)
return valid_ciphers[i].cipher;
i++;
}
return NULL;

View File

@@ -51,21 +51,21 @@ IF(WITH_SSL AND OPENSSL_FOUND)
STRING(REPLACE "\n" "" FINGER_PRINT "${FINGER_PRINT}")
STRING(REPLACE ":" "" SSL_CERT_FINGER_PRINT "${FINGER_PRINT}")
ENDIF()
CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/unittest/libmariadb/ssl.c.in
${CMAKE_SOURCE_DIR}/unittest/libmariadb/ssl.c)
CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/unittest/libmariadb/fingerprint.list.in
${CMAKE_SOURCE_DIR}/unittest/libmariadb/fingerprint.list)
SET(API_TESTS ${API_TESTS} "ssl")
ENDIF()
SET(API_TESTS ${API_TESTS} "ssl")
FOREACH(API_TEST ${API_TESTS})
ADD_EXECUTABLE(${API_TEST} ${API_TEST}.c ${CMAKE_SOURCE_DIR}/libmariadb/getopt.c)
TARGET_LINK_LIBRARIES(${API_TEST} mytap libmariadb)
TARGET_LINK_LIBRARIES(${API_TEST} mytap mariadbclient)
ADD_TEST(${API_TEST} ${EXECUTABLE_OUTPUT_PATH}/${API_TEST})
SET_TESTS_PROPERTIES(${API_TEST} PROPERTIES TIMEOUT 120)
ENDFOREACH(API_TEST)
FOREACH(API_TEST ${MANUAL_TESTS})
ADD_EXECUTABLE(${API_TEST} ${API_TEST}.c ${CMAKE_SOURCE_DIR}/libmariadb/getopt.c)
TARGET_LINK_LIBRARIES(${API_TEST} mytap libmariadb)
TARGET_LINK_LIBRARIES(${API_TEST} mytap mariadbclient)
ENDFOREACH()

View File

@@ -793,6 +793,33 @@ static int test_ssl_version(MYSQL *mysql)
return OK;
}
#ifdef HAVE_SCHANNEL
static int test_schannel_cipher(MYSQL *mysql)
{
MYSQL *my;
unsigned int cipher_strength= 256;
if (check_skip_ssl())
return SKIP;
my= mysql_init(NULL);
FAIL_IF(!my, "mysql_init() failed");
mysql_ssl_set(my,0, 0, "@CMAKE_SOURCE_DIR@/unittest/libmariadb/certs/ca-cert.pem", 0, 0);
mysql_options(my, MARIADB_OPT_SSL_CIPHER_STRENGTH, &cipher_strength);
FAIL_IF(!mysql_real_connect(my, hostname, ssluser, sslpw, schema,
port, socketname, 0), mysql_error(my));
diag("cipher: %s", mysql_get_ssl_cipher(my));
FAIL_IF(strcmp(mysql_get_ssl_cipher(my), "CALG_AES_256") != 0, "expected cipher with 256bit strength");
mysql_close(my);
return OK;
}
#endif
struct my_tests_st my_tests[] = {
@@ -816,6 +843,8 @@ struct my_tests_st my_tests[] = {
{"test_ssl_threads", test_ssl_threads, TEST_CONNECTION_NEW, 0, NULL, NULL},
#ifndef HAVE_SCHANNEL
{"test_password_protected", test_password_protected, TEST_CONNECTION_NEW, 0, NULL, NULL},
#else
{"test_schannel_cipher", test_schannel_cipher, TEST_CONNECTION_NEW, 0, NULL, NULL},
#endif
{NULL, NULL, 0, 0, NULL, NULL}
};