/* establish SSL connection between client and server SYNOPSIS my_ssl_connect ssl ssl object RETURN VALUES 0 success 1 error */ int my_ssl_connect(SSL *ssl) { my_bool blocking; MYSQL *mysql; DBUG_ENTER("my_ssl_connect"); DBUG_ASSERT(ssl != NULL); mysql= (MYSQL *)SSL_get_app_data(ssl); CLEAR_CLIENT_ERROR(mysql); /* Set socket to blocking if not already set */ if (!(blocking= vio_is_blocking(mysql->net.vio))) vio_blocking(mysql->net.vio, TRUE); SSL_clear(ssl); SSL_SESSION_set_timeout(SSL_get_session(ssl), mysql->options.connect_timeout); SSL_set_fd(ssl, mysql->net.vio->sd); if (SSL_connect(ssl) != 1) { my_SSL_error(mysql); /* restore blocking mode */ if (!blocking) vio_blocking(mysql->net.vio, FALSE); DBUG_RETURN(1); } vio_reset(mysql->net.vio, VIO_TYPE_SSL, mysql->net.vio->sd, 0, 0); mysql->net.vio->ssl= ssl; DBUG_RETURN(0); }
/* establish SSL connection between client and server SYNOPSIS my_ssl_connect ssl ssl object RETURN VALUES 0 success 1 error */ int my_ssl_connect(SSL *ssl) { my_bool blocking; MYSQL *mysql; long rc; my_bool try_connect= 1; DBUG_ENTER("my_ssl_connect"); DBUG_ASSERT(ssl != NULL); mysql= (MYSQL *)SSL_get_app_data(ssl); CLEAR_CLIENT_ERROR(mysql); /* Set socket to non blocking */ if (!(blocking= vio_is_blocking(mysql->net.vio))) vio_blocking(mysql->net.vio, FALSE, 0); SSL_clear(ssl); SSL_SESSION_set_timeout(SSL_get_session(ssl), mysql->options.connect_timeout); SSL_set_fd(ssl, mysql->net.vio->sd); while (try_connect && (rc= SSL_connect(ssl)) == -1) { switch(SSL_get_error(ssl, rc)) { case SSL_ERROR_WANT_READ: if (vio_wait_or_timeout(mysql->net.vio, TRUE, mysql->options.connect_timeout) < 1) try_connect= 0; break; case SSL_ERROR_WANT_WRITE: if (vio_wait_or_timeout(mysql->net.vio, TRUE, mysql->options.connect_timeout) < 1) try_connect= 0; break; default: try_connect= 0; } } if (rc != 1) { my_SSL_error(mysql); DBUG_RETURN(1); } rc= SSL_get_verify_result(ssl); if (rc != X509_V_OK) { my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, ER(CR_SSL_CONNECTION_ERROR), X509_verify_cert_error_string(rc)); /* restore blocking mode */ if (!blocking) vio_blocking(mysql->net.vio, FALSE, 0); DBUG_RETURN(1); } vio_reset(mysql->net.vio, VIO_TYPE_SSL, mysql->net.vio->sd, 0, 0); mysql->net.vio->ssl= ssl; DBUG_RETURN(0); }
/* {{{ my_bool ma_pvio_start_ssl */ my_bool ma_pvio_start_ssl(MARIADB_PVIO *pvio) { if (!pvio || !pvio->mysql) return 1; CLEAR_CLIENT_ERROR(pvio->mysql); if (!(pvio->cssl= ma_pvio_ssl_init(pvio->mysql))) { return 1; } if (ma_pvio_ssl_connect(pvio->cssl)) { my_free(pvio->cssl); pvio->cssl= NULL; return 1; } if ((pvio->mysql->options.ssl_ca || pvio->mysql->options.ssl_capath) && (pvio->mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT) && ma_pvio_ssl_verify_server_cert(pvio->cssl)) return 1; if (pvio->mysql->options.extension && (pvio->mysql->options.extension->ssl_fp || pvio->mysql->options.extension->ssl_fp_list)) { if (ma_pvio_ssl_check_fp(pvio->cssl, pvio->mysql->options.extension->ssl_fp, pvio->mysql->options.extension->ssl_fp_list)) return 1; } return 0; }
/* establish SSL connection between client and server SYNOPSIS my_ssl_connect ssl ssl object RETURN VALUES 0 success 1 error */ int my_ssl_connect(SSL *ssl) { my_bool blocking; MYSQL *mysql; long rc; DBUG_ENTER("my_ssl_connect"); DBUG_ASSERT(ssl != NULL); mysql= (MYSQL *)SSL_get_app_data(ssl); CLEAR_CLIENT_ERROR(mysql); /* Set socket to blocking if not already set */ if (!(blocking= vio_is_blocking(mysql->net.vio))) vio_blocking(mysql->net.vio, TRUE, 0); SSL_clear(ssl); SSL_SESSION_set_timeout(SSL_get_session(ssl), mysql->options.connect_timeout); SSL_set_fd(ssl, mysql->net.vio->sd); if (SSL_connect(ssl) != 1) { my_SSL_error(mysql); /* restore blocking mode */ if (!blocking) vio_blocking(mysql->net.vio, FALSE, 0); DBUG_RETURN(1); } rc= SSL_get_verify_result(ssl); if (rc != X509_V_OK) { my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, ER(CR_SSL_CONNECTION_ERROR), X509_verify_cert_error_string(rc)); /* restore blocking mode */ if (!blocking) vio_blocking(mysql->net.vio, FALSE, 0); DBUG_RETURN(1); } vio_reset(mysql->net.vio, VIO_TYPE_SSL, mysql->net.vio->sd, 0, 0); mysql->net.vio->ssl= ssl; DBUG_RETURN(0); }
/* {{{ my_bool ma_pvio_start_ssl */ my_bool ma_pvio_start_ssl(MARIADB_PVIO *pvio) { if (!pvio || !pvio->mysql) return 1; CLEAR_CLIENT_ERROR(pvio->mysql); if (!(pvio->ctls= ma_pvio_tls_init(pvio->mysql))) { return 1; } if (ma_pvio_tls_connect(pvio->ctls)) { free(pvio->ctls); pvio->ctls= NULL; return 1; } /* default behaviour: 1. peer certificate verification 2. verify CN (requires option ssl_verify_check) 3. verrify finger print */ if ((pvio->mysql->options.ssl_ca || pvio->mysql->options.ssl_capath) && (pvio->mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT) && ma_pvio_tls_verify_server_cert(pvio->ctls)) return 1; if (pvio->mysql->options.extension && (pvio->mysql->options.extension->tls_fp && pvio->mysql->options.extension->tls_fp[0]) || (pvio->mysql->options.extension->tls_fp_list && pvio->mysql->options.extension->tls_fp_list[0])) { if (ma_pvio_tls_check_fp(pvio->ctls, pvio->mysql->options.extension->tls_fp, pvio->mysql->options.extension->tls_fp_list)) return 1; } return 0; }
static int my_verify_callback(gnutls_session_t ssl) { unsigned int status; const gnutls_datum_t *cert_list; unsigned int cert_list_size; int ret; MYSQL *mysql= (MYSQL *)gnutls_session_get_ptr(ssl); MARIADB_PVIO *pvio= mysql->net.pvio; gnutls_x509_crt_t cert; const char *hostname; /* read hostname */ hostname = mysql->host; /* skip verification if no ca_file/path was specified */ if (!mysql->options.ssl_ca) return 0; /* This verification function uses the trusted CAs in the credentials * structure. So you must have installed one or more CA certificates. */ ret = gnutls_certificate_verify_peers2 (ssl, &status); if (ret < 0) { pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "CA verification failed"); return GNUTLS_E_CERTIFICATE_ERROR; } // mysql->net.vio->status= status; if (status & GNUTLS_CERT_INVALID) { return GNUTLS_E_CERTIFICATE_ERROR; } /* Up to here the process is the same for X.509 certificates and * OpenPGP keys. From now on X.509 certificates are assumed. This can * be easily extended to work with openpgp keys as well. */ if (gnutls_certificate_type_get (ssl) != GNUTLS_CRT_X509) { pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Expected X509 certificate"); return GNUTLS_E_CERTIFICATE_ERROR; } if (gnutls_x509_crt_init (&cert) < 0) { pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Error during certificate initialization"); return GNUTLS_E_CERTIFICATE_ERROR; } cert_list = gnutls_certificate_get_peers (ssl, &cert_list_size); if (cert_list == NULL) { gnutls_x509_crt_deinit (cert); pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "No certificate found"); return GNUTLS_E_CERTIFICATE_ERROR; } if (gnutls_x509_crt_import (cert, &cert_list[0], GNUTLS_X509_FMT_DER) < 0) { gnutls_x509_crt_deinit (cert); pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Unknown SSL error"); return GNUTLS_E_CERTIFICATE_ERROR; } if ((mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT) && !gnutls_x509_crt_check_hostname (cert, hostname)) { gnutls_x509_crt_deinit (cert); pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Hostname in certificate doesn't match"); return GNUTLS_E_CERTIFICATE_ERROR; } gnutls_x509_crt_deinit (cert); /* notify gnutls to continue handshake normally */ CLEAR_CLIENT_ERROR(mysql); return 0; }