/* MySQL / MariaDB SSL/TLS version check program * * This connects to MySQL / MariaDB port, attempts to establish TLS connection, * and prints TLS session information (including negotiated protocol and cipher * suite). Arguments: * - host (default: localhost) * - port (default: 3306) * - method (default: SSLv23, valid: SSLv23, SSLv2, SSLv3, TLSv1, TLSv1_1, TLSv1_2) * - cipher string (default: none) */ #include #include #include #include #include #include #include #include #include #include // handle mysql protocol prior to TLS handshake int mysql_pre_ssl(int sock) { char buf[512]; size_t plen; // greeting packet len read(sock, buf, 3); plen = buf[0] + (buf[1] << 8) + (buf[2] << 16); // version banner from the greeting read(sock, buf+3, plen+1); printf("MySQL server version: %s\n", buf+5); // empty client login request memcpy(buf, "\x20\x00\x00\x01\x85\xae\x03\x00\x00\x00\x00" "\x01\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32+4); write(sock, buf, 32+4); return 0; } int make_connection(const char *host, int port, SSL_CTX *ctx) { int sock; struct hostent *hp; struct sockaddr_in server_addr; SSL *ssl; BIO *bio; hp = gethostbyname(host); memset(&server_addr, '\0', sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); memcpy(&(server_addr.sin_addr.s_addr), hp->h_addr, hp->h_length); sock = socket(AF_INET, SOCK_STREAM, 0); if (connect(sock, (struct sockaddr*) &server_addr, sizeof(server_addr)) < 0) { fprintf(stderr, "connect error: %s\n", strerror(errno)); return 1; } mysql_pre_ssl(sock); ssl = SSL_new(ctx); bio = BIO_new_socket(sock, BIO_NOCLOSE); SSL_set_bio(ssl, bio, bio); if (SSL_connect(ssl) != 1) { fprintf(stderr, "ssl connect error: %s\n", ERR_error_string(ERR_get_error(), NULL)); return 1; } SSL_SESSION_print_fp(stdout, SSL_get_session(ssl)); if (!SSL_shutdown(ssl)) SSL_shutdown(ssl); SSL_free(ssl); close(sock); return 0; } int main(int argc, char *argv[]) { char *host = "localhost"; int port = 3306; char *meth_name = "SSLv23"; char *ciphers = NULL; SSL_CTX *ctx; if (argc >= 2) host = argv[1]; if (argc >= 3) port = atoi(argv[2]); if (argc >= 4) meth_name = argv[3]; if (argc >= 5) ciphers = argv[4]; SSL_library_init(); SSL_load_error_strings(); ERR_load_BIO_strings(); OpenSSL_add_all_algorithms(); if (strcmp(meth_name, "SSLv23") == 0) ctx = SSL_CTX_new(SSLv23_client_method()); else if (strcmp(meth_name, "SSLv2") == 0) ctx = SSL_CTX_new(SSLv2_client_method()); else if (strcmp(meth_name, "SSLv3") == 0) ctx = SSL_CTX_new(SSLv3_client_method()); else if (strcmp(meth_name, "TLSv1") == 0) ctx = SSL_CTX_new(TLSv1_client_method()); else if (strcmp(meth_name, "TLSv1_1") == 0) { #ifdef SSL_OP_NO_TLSv1_1 ctx = SSL_CTX_new(TLSv1_1_client_method()); #else fprintf(stderr, "error: installed OpenSSL version does not support: %s\n", meth_name); exit(1); #endif } else if (strcmp(meth_name, "TLSv1_2") == 0) { #ifdef SSL_OP_NO_TLSv1_2 ctx = SSL_CTX_new(TLSv1_2_client_method()); #else fprintf(stderr, "error: installed OpenSSL version does not support: %s\n", meth_name); exit(1); #endif } else { fprintf(stderr, "error: unknown SSL/TLS method: %s\n", meth_name); exit(1); } if (ctx == NULL) { fprintf(stderr, "error: SSL_CTX is NULL\n"); exit(1); } if (ciphers) SSL_CTX_set_cipher_list(ctx, ciphers); printf("Connecting to: %s:%d, using method: %s\n", host, port, meth_name); return make_connection(host, port, ctx); }