1 /* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    Without limiting anything contained in the foregoing, this file,
15    which is part of C Driver for MySQL (Connector/C), is also subject to the
16    Universal FOSS Exception, version 1.0, a copy of which can be found at
17    http://oss.oracle.com/licenses/universal-foss-exception.
18 
19    This program is distributed in the hope that it will be useful,
20    but WITHOUT ANY WARRANTY; without even the implied warranty of
21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22    GNU General Public License, version 2.0, for more details.
23 
24    You should have received a copy of the GNU General Public License
25    along with this program; if not, write to the Free Software
26    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
27 
28 #include "vio_priv.h"
29 
30 #ifdef HAVE_OPENSSL
31 
32 #define TLS_VERSION_OPTION_SIZE 256
33 #define SSL_CIPHER_LIST_SIZE 4096
34 
35 static const char tls_ciphers_list[]="ECDHE-ECDSA-AES128-GCM-SHA256:"
36   "ECDHE-ECDSA-AES256-GCM-SHA384:"
37   "ECDHE-RSA-AES128-GCM-SHA256:"
38   "ECDHE-RSA-AES256-GCM-SHA384:"
39   "ECDHE-ECDSA-AES128-SHA256:"
40   "ECDHE-RSA-AES128-SHA256:"
41   "ECDHE-ECDSA-AES256-SHA384:"
42   "ECDHE-RSA-AES256-SHA384:"
43   "DHE-RSA-AES128-GCM-SHA256:"
44   "DHE-DSS-AES128-GCM-SHA256:"
45   "DHE-RSA-AES128-SHA256:"
46   "DHE-DSS-AES128-SHA256:"
47   "DHE-DSS-AES256-GCM-SHA384:"
48   "DHE-RSA-AES256-SHA256:"
49   "DHE-DSS-AES256-SHA256:"
50   "ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:"
51   "ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:"
52   "DHE-DSS-AES128-SHA:DHE-RSA-AES128-SHA:"
53   "TLS_DHE_DSS_WITH_AES_256_CBC_SHA:DHE-RSA-AES256-SHA:"
54   "AES128-GCM-SHA256:DH-DSS-AES128-GCM-SHA256:"
55   "ECDH-ECDSA-AES128-GCM-SHA256:AES256-GCM-SHA384:"
56   "DH-DSS-AES256-GCM-SHA384:ECDH-ECDSA-AES256-GCM-SHA384:"
57   "AES128-SHA256:DH-DSS-AES128-SHA256:ECDH-ECDSA-AES128-SHA256:AES256-SHA256:"
58   "DH-DSS-AES256-SHA256:ECDH-ECDSA-AES256-SHA384:AES128-SHA:"
59   "DH-DSS-AES128-SHA:ECDH-ECDSA-AES128-SHA:AES256-SHA:"
60   "DH-DSS-AES256-SHA:ECDH-ECDSA-AES256-SHA:DHE-RSA-AES256-GCM-SHA384:"
61   "DH-RSA-AES128-GCM-SHA256:ECDH-RSA-AES128-GCM-SHA256:DH-RSA-AES256-GCM-SHA384:"
62   "ECDH-RSA-AES256-GCM-SHA384:DH-RSA-AES128-SHA256:"
63   "ECDH-RSA-AES128-SHA256:DH-RSA-AES256-SHA256:"
64   "ECDH-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:"
65   "ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA:"
66   "ECDHE-ECDSA-AES256-SHA:DHE-DSS-AES128-SHA:DHE-RSA-AES128-SHA:"
67   "TLS_DHE_DSS_WITH_AES_256_CBC_SHA:DHE-RSA-AES256-SHA:"
68   "AES128-SHA:DH-DSS-AES128-SHA:ECDH-ECDSA-AES128-SHA:AES256-SHA:"
69   "DH-DSS-AES256-SHA:ECDH-ECDSA-AES256-SHA:DH-RSA-AES128-SHA:"
70   "ECDH-RSA-AES128-SHA:DH-RSA-AES256-SHA:ECDH-RSA-AES256-SHA:DES-CBC3-SHA";
71 static const char tls_cipher_blocked[]= "!aNULL:!eNULL:!EXPORT:!LOW:!MD5:!DES:!RC2:!RC4:!PSK:"
72   "!DHE-DSS-DES-CBC3-SHA:!DHE-RSA-DES-CBC3-SHA:"
73   "!ECDH-RSA-DES-CBC3-SHA:!ECDH-ECDSA-DES-CBC3-SHA:"
74   "!ECDHE-RSA-DES-CBC3-SHA:!ECDHE-ECDSA-DES-CBC3-SHA:";
75 
76 
77 static my_bool     ssl_algorithms_added    = FALSE;
78 static my_bool     ssl_error_strings_loaded= FALSE;
79 
80 /*
81   Diffie-Hellman key.
82   Generated using: >openssl dhparam -5 -C 2048
83 
84   -----BEGIN DH PARAMETERS-----
85   MIIBCAKCAQEAil36wGZ2TmH6ysA3V1xtP4MKofXx5n88xq/aiybmGnReZMviCPEJ
86   46+7VCktl/RZ5iaDH1XNG1dVQmznt9pu2G3usU+k1/VB4bQL4ZgW4u0Wzxh9PyXD
87   glm99I9Xyj4Z5PVE4MyAsxCRGA1kWQpD9/zKAegUBPLNqSo886Uqg9hmn8ksyU9E
88   BV5eAEciCuawh6V0O+Sj/C3cSfLhgA0GcXp3OqlmcDu6jS5gWjn3LdP1U0duVxMB
89   h/neTSCSvtce4CAMYMjKNVh9P1nu+2d9ZH2Od2xhRIqMTfAS1KTqF3VmSWzPFCjG
90   mjxx/bg6bOOjpgZapvB6ABWlWmRmAAWFtwIBBQ==
91   -----END DH PARAMETERS-----
92  */
93 static unsigned char dh2048_p[]=
94 {
95   0x8A, 0x5D, 0xFA, 0xC0, 0x66, 0x76, 0x4E, 0x61, 0xFA, 0xCA, 0xC0, 0x37,
96   0x57, 0x5C, 0x6D, 0x3F, 0x83, 0x0A, 0xA1, 0xF5, 0xF1, 0xE6, 0x7F, 0x3C,
97   0xC6, 0xAF, 0xDA, 0x8B, 0x26, 0xE6, 0x1A, 0x74, 0x5E, 0x64, 0xCB, 0xE2,
98   0x08, 0xF1, 0x09, 0xE3, 0xAF, 0xBB, 0x54, 0x29, 0x2D, 0x97, 0xF4, 0x59,
99   0xE6, 0x26, 0x83, 0x1F, 0x55, 0xCD, 0x1B, 0x57, 0x55, 0x42, 0x6C, 0xE7,
100   0xB7, 0xDA, 0x6E, 0xD8, 0x6D, 0xEE, 0xB1, 0x4F, 0xA4, 0xD7, 0xF5, 0x41,
101   0xE1, 0xB4, 0x0B, 0xE1, 0x98, 0x16, 0xE2, 0xED, 0x16, 0xCF, 0x18, 0x7D,
102   0x3F, 0x25, 0xC3, 0x82, 0x59, 0xBD, 0xF4, 0x8F, 0x57, 0xCA, 0x3E, 0x19,
103   0xE4, 0xF5, 0x44, 0xE0, 0xCC, 0x80, 0xB3, 0x10, 0x91, 0x18, 0x0D, 0x64,
104   0x59, 0x0A, 0x43, 0xF7, 0xFC, 0xCA, 0x01, 0xE8, 0x14, 0x04, 0xF2, 0xCD,
105   0xA9, 0x2A, 0x3C, 0xF3, 0xA5, 0x2A, 0x83, 0xD8, 0x66, 0x9F, 0xC9, 0x2C,
106   0xC9, 0x4F, 0x44, 0x05, 0x5E, 0x5E, 0x00, 0x47, 0x22, 0x0A, 0xE6, 0xB0,
107   0x87, 0xA5, 0x74, 0x3B, 0xE4, 0xA3, 0xFC, 0x2D, 0xDC, 0x49, 0xF2, 0xE1,
108   0x80, 0x0D, 0x06, 0x71, 0x7A, 0x77, 0x3A, 0xA9, 0x66, 0x70, 0x3B, 0xBA,
109   0x8D, 0x2E, 0x60, 0x5A, 0x39, 0xF7, 0x2D, 0xD3, 0xF5, 0x53, 0x47, 0x6E,
110   0x57, 0x13, 0x01, 0x87, 0xF9, 0xDE, 0x4D, 0x20, 0x92, 0xBE, 0xD7, 0x1E,
111   0xE0, 0x20, 0x0C, 0x60, 0xC8, 0xCA, 0x35, 0x58, 0x7D, 0x3F, 0x59, 0xEE,
112   0xFB, 0x67, 0x7D, 0x64, 0x7D, 0x8E, 0x77, 0x6C, 0x61, 0x44, 0x8A, 0x8C,
113   0x4D, 0xF0, 0x12, 0xD4, 0xA4, 0xEA, 0x17, 0x75, 0x66, 0x49, 0x6C, 0xCF,
114   0x14, 0x28, 0xC6, 0x9A, 0x3C, 0x71, 0xFD, 0xB8, 0x3A, 0x6C, 0xE3, 0xA3,
115   0xA6, 0x06, 0x5A, 0xA6, 0xF0, 0x7A, 0x00, 0x15, 0xA5, 0x5A, 0x64, 0x66,
116   0x00, 0x05, 0x85, 0xB7,
117 };
118 
119 static unsigned char dh2048_g[]={
120   0x05,
121 };
122 
get_dh2048(void)123 static DH *get_dh2048(void)
124 {
125   DH *dh;
126   if ((dh=DH_new()))
127   {
128     BIGNUM *p= BN_bin2bn(dh2048_p, sizeof(dh2048_p), NULL);
129     BIGNUM *g= BN_bin2bn(dh2048_g, sizeof(dh2048_g), NULL);
130     if (!p || !g
131 #if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined( LIBRESSL_VERSION_NUMBER )
132         || !DH_set0_pqg(dh, p, NULL, g)
133 #endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
134     ) {
135       /* DH_free() will free 'p' and 'g' at once. */
136       DH_free(dh);
137       return NULL;
138     }
139 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined( LIBRESSL_VERSION_NUMBER )
140     dh->p= p;
141     dh->g= g;
142 #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
143   }
144   return(dh);
145 }
146 
147 
148 static void
report_errors()149 report_errors()
150 {
151   unsigned long	l;
152   const char*	file;
153   const char*	data;
154   int		line,flags;
155 
156   DBUG_ENTER("report_errors");
157 
158   while ((l=ERR_get_error_line_data(&file,&line,&data,&flags)) != 0)
159   {
160 #ifndef DBUG_OFF				/* Avoid warning */
161     char buf[200];
162     DBUG_PRINT("error", ("OpenSSL: %s:%s:%d:%s\n", ERR_error_string(l,buf),
163 			 file,line,(flags & ERR_TXT_STRING) ? data : "")) ;
164 #endif
165   }
166   DBUG_VOID_RETURN;
167 }
168 
169 static const char*
170 ssl_error_string[] =
171 {
172   "No error",
173   "Unable to get certificate",
174   "Unable to get private key",
175   "Private key does not match the certificate public key",
176   "SSL_CTX_set_default_verify_paths failed",
177   "Failed to set ciphers to use",
178   "SSL_CTX_new failed",
179   "SSL_CTX_set_tmp_dh failed"
180 };
181 
182 const char*
sslGetErrString(enum enum_ssl_init_error e)183 sslGetErrString(enum enum_ssl_init_error e)
184 {
185   DBUG_ASSERT(SSL_INITERR_NOERROR < e && e < SSL_INITERR_LASTERR);
186   return ssl_error_string[e];
187 }
188 
189 static int
vio_set_cert_stuff(SSL_CTX * ctx,const char * cert_file,const char * key_file,enum enum_ssl_init_error * error)190 vio_set_cert_stuff(SSL_CTX *ctx, const char *cert_file, const char *key_file,
191                    enum enum_ssl_init_error* error)
192 {
193   DBUG_ENTER("vio_set_cert_stuff");
194   DBUG_PRINT("enter", ("ctx: 0x%lx  cert_file: %s  key_file: %s",
195 		       (long) ctx, cert_file, key_file));
196 
197   if (!cert_file &&  key_file)
198     cert_file= key_file;
199 
200   if (!key_file &&  cert_file)
201     key_file= cert_file;
202 
203   if (cert_file &&
204       SSL_CTX_use_certificate_file(ctx, cert_file, SSL_FILETYPE_PEM) <= 0)
205   {
206     *error= SSL_INITERR_CERT;
207     DBUG_PRINT("error",("%s from file '%s'", sslGetErrString(*error), cert_file));
208     DBUG_EXECUTE("error", ERR_print_errors_fp(DBUG_FILE););
209     fprintf(stderr, "SSL error: %s from '%s'\n", sslGetErrString(*error),
210             cert_file);
211     fflush(stderr);
212     DBUG_RETURN(1);
213   }
214 
215   if (key_file &&
216       SSL_CTX_use_PrivateKey_file(ctx, key_file, SSL_FILETYPE_PEM) <= 0)
217   {
218     *error= SSL_INITERR_KEY;
219     DBUG_PRINT("error", ("%s from file '%s'", sslGetErrString(*error), key_file));
220     DBUG_EXECUTE("error", ERR_print_errors_fp(DBUG_FILE););
221     fprintf(stderr, "SSL error: %s from '%s'\n", sslGetErrString(*error),
222             key_file);
223     fflush(stderr);
224     DBUG_RETURN(1);
225   }
226 
227   /*
228     If we are using DSA, we can copy the parameters from the private key
229     Now we know that a key and cert have been set against the SSL context
230   */
231   if (cert_file && !SSL_CTX_check_private_key(ctx))
232   {
233     *error= SSL_INITERR_NOMATCH;
234     DBUG_PRINT("error", ("%s",sslGetErrString(*error)));
235     DBUG_EXECUTE("error", ERR_print_errors_fp(DBUG_FILE););
236     fprintf(stderr, "SSL error: %s\n", sslGetErrString(*error));
237     fflush(stderr);
238     DBUG_RETURN(1);
239   }
240 
241   DBUG_RETURN(0);
242 }
243 
244 
ssl_start()245 void ssl_start()
246 {
247   if (!ssl_algorithms_added)
248   {
249     ssl_algorithms_added= TRUE;
250     SSL_library_init();
251     OpenSSL_add_all_algorithms();
252 
253   }
254 
255   if (!ssl_error_strings_loaded)
256   {
257     ssl_error_strings_loaded= TRUE;
258     SSL_load_error_strings();
259   }
260 }
261 
process_tls_version(const char * tls_version)262 long process_tls_version(const char *tls_version)
263 {
264   const char *separator= ",";
265   char *token, *lasts= NULL;
266 
267   const char *tls_version_name_list[]= {"TLSv1"
268 #ifdef SSL_OP_NO_TLSv1_1
269                                         ,"TLSv1.1"
270 #endif
271 #ifdef SSL_OP_NO_TLSv1_2
272                                         ,"TLSv1.2"
273 #endif
274                                        };
275 
276   const char ctx_flag_default[]=
277 #ifdef SSL_OP_NO_TLSv1_2
278   "TLSv1.1,TLSv1.2";
279 #elif defined(SSL_OP_NO_TLSv1_1)
280   "TLSv1.1";
281 #else
282   "TLSv1";
283 #endif
284 
285   const long tls_ctx_list[]= {SSL_OP_NO_TLSv1
286 #ifdef SSL_OP_NO_TLSv1_1
287                               ,SSL_OP_NO_TLSv1_1
288 #endif
289 #ifdef SSL_OP_NO_TLSv1_2
290                               ,SSL_OP_NO_TLSv1_2
291 #endif
292                              };
293   size_t tls_versions_count= sizeof(tls_ctx_list) / sizeof(tls_ctx_list[0]);
294   long tls_ctx_flag= 0;
295   unsigned int index= 0;
296   char tls_version_option[TLS_VERSION_OPTION_SIZE]= "";
297   int tls_found= 0;
298 
299   for (index = 0; index < tls_versions_count; index++)
300       tls_ctx_flag|= tls_ctx_list[index];
301 
302   if (!tls_version || !my_strcasecmp(&my_charset_latin1, tls_version,
303                                      ctx_flag_default))
304     return 0;
305 
306   if (strlen(tls_version)-1 > sizeof(tls_version_option))
307     return -1;
308 
309   strncpy(tls_version_option, tls_version, sizeof(tls_version_option));
310   token= my_strtok_r(tls_version_option, separator, &lasts);
311   while (token)
312   {
313     for (index=0; index < tls_versions_count; index++)
314     {
315       if (!my_strcasecmp(&my_charset_latin1, tls_version_name_list[index],
316                          token))
317       {
318         tls_found= 1;
319         tls_ctx_flag= tls_ctx_flag & (~tls_ctx_list[index]);
320         break;
321       }
322     }
323     token= my_strtok_r(NULL, separator, &lasts);
324   }
325 
326   if (!tls_found)
327     return -1;
328   else
329     return tls_ctx_flag;
330 }
331 
332 /************************ VioSSLFd **********************************/
333 static struct st_VioSSLFd *
new_VioSSLFd(const char * key_file,const char * cert_file,const char * ca_file,const char * ca_path,const char * cipher,my_bool is_client,enum enum_ssl_init_error * error,const char * crl_file,const char * crl_path,const long ssl_ctx_flags)334 new_VioSSLFd(const char *key_file, const char *cert_file,
335              const char *ca_file, const char *ca_path,
336              const char *cipher, my_bool is_client,
337              enum enum_ssl_init_error *error,
338              const char *crl_file, const char *crl_path,
339              const long ssl_ctx_flags)
340 {
341   DH *dh;
342   struct st_VioSSLFd *ssl_fd;
343   /* MySQL 5.6 supports TLS up to v1.2, explicitly disable TLSv1.3. */
344   long ssl_ctx_options= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
345 #if !defined(LIBRESSL_VERSION_NUMBER) || defined(SSL_OP_NO_TLSv1_3)
346 #ifdef HAVE_TLSv13
347                         SSL_OP_NO_TLSv1_3 |
348 #endif /* HAVE_TLSv13 */
349 #endif
350                         SSL_OP_NO_TICKET;
351   int ret_set_cipherlist= 0;
352   char cipher_list[SSL_CIPHER_LIST_SIZE]= {0};
353 #if defined(OPENSSL_EC_NAMED_CURVE) && (OPENSSL_VERSION_NUMBER < 0x10002000L)
354   EC_KEY *ecdh;
355 #endif
356   DBUG_ENTER("new_VioSSLFd");
357   DBUG_PRINT("enter",
358              ("key_file: '%s'  cert_file: '%s'  ca_file: '%s'  ca_path: '%s'  "
359               "cipher: '%s' crl_file: '%s' crl_path: '%s'  flags: '%lX'",
360               key_file ? key_file : "NULL",
361               cert_file ? cert_file : "NULL",
362               ca_file ? ca_file : "NULL",
363               ca_path ? ca_path : "NULL",
364               cipher ? cipher : "NULL",
365               crl_file ? crl_file : "NULL",
366               crl_path ? crl_path : "NULL",
367               ssl_ctx_flags));
368 
369   if (ssl_ctx_flags < 0)
370   {
371     *error= SSL_TLS_VERSION_INVALID;
372     DBUG_PRINT("error", ("TLS version invalid : %s", sslGetErrString(*error)));
373     report_errors();
374     DBUG_RETURN(0);
375   }
376 
377   ssl_ctx_options= (ssl_ctx_options | ssl_ctx_flags) &
378     (SSL_OP_NO_SSLv2 |
379      SSL_OP_NO_SSLv3 |
380 #if !defined(LIBRESSL_VERSION_NUMBER) || defined(SSL_OP_NO_TLSv1_3)
381 #ifdef HAVE_TLSv13
382      SSL_OP_NO_TLSv1_3 |
383 #endif /* HAVE_TLSv13 */
384 #endif
385      SSL_OP_NO_TLSv1
386 #ifdef SSL_OP_NO_TLSv1_1
387      | SSL_OP_NO_TLSv1_1
388 #endif
389 #ifdef SSL_OP_NO_TLSv1_2
390      | SSL_OP_NO_TLSv1_2
391 #endif
392      );
393 
394   ssl_start();
395 
396   if (!(ssl_fd= ((struct st_VioSSLFd*)
397                  my_malloc(sizeof(struct st_VioSSLFd),MYF(0)))))
398     DBUG_RETURN(0);
399 
400   if (!(ssl_fd->ssl_context= SSL_CTX_new(is_client ?
401 #if OPENSSL_VERSION_NUMBER < 0x10100000L
402                                          SSLv23_client_method() :
403                                          SSLv23_server_method()
404 #else /* OPENSSL_VERSION_NUMBER < 0x10100000L */
405                                          TLS_client_method() :
406                                          TLS_server_method()
407 #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
408                                         )))
409   {
410     *error= SSL_INITERR_MEMFAIL;
411     DBUG_PRINT("error", ("%s", sslGetErrString(*error)));
412     report_errors();
413     my_free(ssl_fd);
414     DBUG_RETURN(0);
415   }
416 
417   SSL_CTX_set_options(ssl_fd->ssl_context, ssl_ctx_options);
418 
419 #ifndef LIBRESSL_VERSION_NUMBER
420 #ifdef HAVE_TLSv13
421   /*
422     MySQL 5.6 doesn't support TLSv1.3 - set empty TLSv1.3 ciphersuites.
423   */
424   if (0 == SSL_CTX_set_ciphersuites(ssl_fd->ssl_context, ""))
425   {
426     *error = SSL_INITERR_CIPHERS;
427     DBUG_PRINT("error", ("%s", sslGetErrString(*error)));
428     report_errors();
429     SSL_CTX_free(ssl_fd->ssl_context);
430     my_free(ssl_fd);
431     DBUG_RETURN(0);
432   }
433 #endif /* HAVE_TLSv13 */
434 #endif
435 
436   /*
437     Set the ciphers that can be used
438     NOTE: SSL_CTX_set_cipher_list will return 0 if
439     none of the provided ciphers could be selected
440   */
441   DBUG_ASSERT(strlen(tls_cipher_blocked) + 1 <= sizeof(cipher_list));
442   strcat(cipher_list, tls_cipher_blocked);
443   if (cipher)
444   {
445     if (strlen(cipher_list) + strlen(cipher) + 1 > sizeof(cipher_list))
446     {
447       *error= SSL_INITERR_CIPHERS;
448       DBUG_PRINT("error", ("User specified cipher too long"));
449       SSL_CTX_free(ssl_fd->ssl_context);
450       my_free(ssl_fd);
451       DBUG_RETURN(0);
452     }
453     strcat(cipher_list, cipher);
454   }
455   else
456   {
457     DBUG_ASSERT(strlen(cipher_list) + strlen(tls_ciphers_list) + 1
458                 <= sizeof(cipher_list));
459     strcat(cipher_list, tls_ciphers_list);
460   }
461 
462   if (ret_set_cipherlist == SSL_CTX_set_cipher_list(ssl_fd->ssl_context,
463                                                     cipher_list))
464   {
465     *error= SSL_INITERR_CIPHERS;
466     DBUG_PRINT("error", ("%s", sslGetErrString(*error)));
467     report_errors();
468     SSL_CTX_free(ssl_fd->ssl_context);
469     my_free(ssl_fd);
470     DBUG_RETURN(0);
471   }
472 
473   /* Load certs from the trusted ca */
474   if (SSL_CTX_load_verify_locations(ssl_fd->ssl_context, ca_file, ca_path) <= 0)
475   {
476     DBUG_PRINT("warning", ("SSL_CTX_load_verify_locations failed"));
477     if (ca_file || ca_path)
478     {
479       /* fail only if ca file or ca path were supplied and looking into
480          them fails. */
481       *error= SSL_INITERR_BAD_PATHS;
482       DBUG_PRINT("error", ("SSL_CTX_load_verify_locations failed : %s",
483                  sslGetErrString(*error)));
484       report_errors();
485       SSL_CTX_free(ssl_fd->ssl_context);
486       my_free(ssl_fd);
487       DBUG_RETURN(0);
488     }
489 
490     /* otherwise go use the defaults */
491     if (SSL_CTX_set_default_verify_paths(ssl_fd->ssl_context) == 0)
492     {
493       *error= SSL_INITERR_BAD_PATHS;
494       DBUG_PRINT("error", ("%s", sslGetErrString(*error)));
495       report_errors();
496       SSL_CTX_free(ssl_fd->ssl_context);
497       my_free(ssl_fd);
498       DBUG_RETURN(0);
499     }
500   }
501 
502   if (crl_file || crl_path)
503   {
504     X509_STORE *store= SSL_CTX_get_cert_store(ssl_fd->ssl_context);
505     /* Load crls from the trusted ca */
506     if (X509_STORE_load_locations(store, crl_file, crl_path) == 0 ||
507         X509_STORE_set_flags(store,
508                              X509_V_FLAG_CRL_CHECK |
509                              X509_V_FLAG_CRL_CHECK_ALL) == 0)
510     {
511       DBUG_PRINT("warning", ("X509_STORE_load_locations for CRL failed"));
512       *error= SSL_INITERR_BAD_PATHS;
513       DBUG_PRINT("error", ("%s", sslGetErrString(*error)));
514       report_errors();
515       SSL_CTX_free(ssl_fd->ssl_context);
516       my_free(ssl_fd);
517       DBUG_RETURN(0);
518     }
519   }
520 
521   if (vio_set_cert_stuff(ssl_fd->ssl_context, cert_file, key_file, error))
522   {
523     DBUG_PRINT("error", ("vio_set_cert_stuff failed"));
524     report_errors();
525     SSL_CTX_free(ssl_fd->ssl_context);
526     my_free(ssl_fd);
527     DBUG_RETURN(0);
528   }
529 
530   /* DH stuff */
531   dh= get_dh2048();
532   if (SSL_CTX_set_tmp_dh(ssl_fd->ssl_context, dh) == 0)
533   {
534     *error= SSL_INITERR_DHFAIL;
535     DBUG_PRINT("error", ("%s", sslGetErrString(*error)));
536     report_errors();
537     DH_free(dh);
538     SSL_CTX_free(ssl_fd->ssl_context);
539     my_free(ssl_fd);
540     DBUG_RETURN(0);
541   }
542   DH_free(dh);
543 
544 #ifdef OPENSSL_EC_NAMED_CURVE
545 #if OPENSSL_VERSION_NUMBER < 0x10002000L
546   ecdh= EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
547   if (!ecdh)
548   {
549     *error= SSL_INITERR_DHFAIL;
550     DBUG_PRINT("error", ("%s", sslGetErrString(*error)));
551     report_errors();
552     SSL_CTX_free(ssl_fd->ssl_context);
553     my_free(ssl_fd);
554     DBUG_RETURN(0);
555   }
556 
557   if (SSL_CTX_set_tmp_ecdh(ssl_fd->ssl_context, ecdh) != 1)
558   {
559     *error= SSL_INITERR_DHFAIL;
560     DBUG_PRINT("error", ("%s", sslGetErrString(*error)));
561     report_errors();
562     EC_KEY_free(ecdh);
563     SSL_CTX_free(ssl_fd->ssl_context);
564     my_free(ssl_fd);
565     DBUG_RETURN(0);
566   }
567   EC_KEY_free(ecdh);
568 
569 #else /* OPENSSL_VERSION_NUMBER < 0x10002000L */
570 
571   if (SSL_CTX_set_ecdh_auto(ssl_fd->ssl_context, 1) != 1)
572   {
573     *error= SSL_INITERR_DHFAIL;
574     DBUG_PRINT("error", ("%s", sslGetErrString(*error)));
575     report_errors();
576     SSL_CTX_free(ssl_fd->ssl_context);
577     my_free(ssl_fd);
578     DBUG_RETURN(0);
579   }
580 #endif /* OPENSSL_VERSION_NUMBER < 0x10002000L */
581 #endif /* OPENSSL_EC_NAMED_CURVE */
582 
583   DBUG_PRINT("exit", ("OK 1"));
584 
585   DBUG_RETURN(ssl_fd);
586 }
587 
588 
589 /************************ VioSSLConnectorFd **********************************/
590 struct st_VioSSLFd *
new_VioSSLConnectorFd(const char * key_file,const char * cert_file,const char * ca_file,const char * ca_path,const char * cipher,enum enum_ssl_init_error * error,const char * crl_file,const char * crl_path,const long ssl_ctx_flags)591 new_VioSSLConnectorFd(const char *key_file, const char *cert_file,
592                       const char *ca_file, const char *ca_path,
593                       const char *cipher, enum enum_ssl_init_error* error,
594                       const char *crl_file, const char *crl_path,
595                       const long ssl_ctx_flags)
596 {
597   struct st_VioSSLFd *ssl_fd;
598   int verify= SSL_VERIFY_PEER;
599 
600   /*
601     Turn off verification of servers certificate if both
602     ca_file and ca_path is set to NULL
603   */
604   if (ca_file == 0 && ca_path == 0)
605     verify= SSL_VERIFY_NONE;
606 
607   if (!(ssl_fd= new_VioSSLFd(key_file, cert_file, ca_file,
608                              ca_path, cipher, TRUE, error,
609                              crl_file, crl_path, ssl_ctx_flags)))
610   {
611     return 0;
612   }
613 
614   /* Init the VioSSLFd as a "connector" ie. the client side */
615 
616   SSL_CTX_set_verify(ssl_fd->ssl_context, verify, NULL);
617 
618   return ssl_fd;
619 }
620 
621 
622 /************************ VioSSLAcceptorFd **********************************/
623 struct st_VioSSLFd *
new_VioSSLAcceptorFd(const char * key_file,const char * cert_file,const char * ca_file,const char * ca_path,const char * cipher,enum enum_ssl_init_error * error,const char * crl_file,const char * crl_path,const long ssl_ctx_flags)624 new_VioSSLAcceptorFd(const char *key_file, const char *cert_file,
625 		     const char *ca_file, const char *ca_path,
626 		     const char *cipher, enum enum_ssl_init_error* error,
627                      const char *crl_file, const char *crl_path,
628                      const long ssl_ctx_flags)
629 {
630   struct st_VioSSLFd *ssl_fd;
631   int verify= SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE;
632   if (!(ssl_fd= new_VioSSLFd(key_file, cert_file, ca_file,
633                              ca_path, cipher, FALSE, error,
634                              crl_file, crl_path, ssl_ctx_flags)))
635   {
636     return 0;
637   }
638   /* Init the the VioSSLFd as a "acceptor" ie. the server side */
639 
640   /* Set max number of cached sessions, returns the previous size */
641   SSL_CTX_sess_set_cache_size(ssl_fd->ssl_context, 128);
642 
643   SSL_CTX_set_verify(ssl_fd->ssl_context, verify, NULL);
644 
645   /*
646     Set session_id - an identifier for this server session
647     Use the ssl_fd pointer
648    */
649   SSL_CTX_set_session_id_context(ssl_fd->ssl_context,
650 				 (const unsigned char *)ssl_fd,
651 				 sizeof(ssl_fd));
652 
653   return ssl_fd;
654 }
655 
free_vio_ssl_acceptor_fd(struct st_VioSSLFd * fd)656 void free_vio_ssl_acceptor_fd(struct st_VioSSLFd *fd)
657 {
658   SSL_CTX_free(fd->ssl_context);
659   my_free(fd);
660 }
661 #endif /* HAVE_OPENSSL */
662