MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
viosslfactories.c
1 /* Copyright (c) 2000, 2011, 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 as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 #include "vio_priv.h"
17 
18 #ifdef HAVE_OPENSSL
19 
20 static my_bool ssl_algorithms_added = FALSE;
21 static my_bool ssl_error_strings_loaded= FALSE;
22 
23 static unsigned char dh512_p[]=
24 {
25  0xDA,0x58,0x3C,0x16,0xD9,0x85,0x22,0x89,0xD0,0xE4,0xAF,0x75,
26  0x6F,0x4C,0xCA,0x92,0xDD,0x4B,0xE5,0x33,0xB8,0x04,0xFB,0x0F,
27  0xED,0x94,0xEF,0x9C,0x8A,0x44,0x03,0xED,0x57,0x46,0x50,0xD3,
28  0x69,0x99,0xDB,0x29,0xD7,0x76,0x27,0x6B,0xA2,0xD3,0xD4,0x12,
29  0xE2,0x18,0xF4,0xDD,0x1E,0x08,0x4C,0xF6,0xD8,0x00,0x3E,0x7C,
30  0x47,0x74,0xE8,0x33,
31 };
32 
33 static unsigned char dh512_g[]={
34  0x02,
35 };
36 
37 static DH *get_dh512(void)
38 {
39  DH *dh;
40  if ((dh=DH_new()))
41  {
42  dh->p=BN_bin2bn(dh512_p,sizeof(dh512_p),NULL);
43  dh->g=BN_bin2bn(dh512_g,sizeof(dh512_g),NULL);
44  if (! dh->p || ! dh->g)
45  {
46  DH_free(dh);
47  dh=0;
48  }
49  }
50  return(dh);
51 }
52 
53 
54 static void
55 report_errors()
56 {
57  unsigned long l;
58  const char* file;
59  const char* data;
60  int line,flags;
61 
62  DBUG_ENTER("report_errors");
63 
64  while ((l=ERR_get_error_line_data(&file,&line,&data,&flags)) != 0)
65  {
66 #ifndef DBUG_OFF /* Avoid warning */
67  char buf[200];
68  DBUG_PRINT("error", ("OpenSSL: %s:%s:%d:%s\n", ERR_error_string(l,buf),
69  file,line,(flags & ERR_TXT_STRING) ? data : "")) ;
70 #endif
71  }
72  DBUG_VOID_RETURN;
73 }
74 
75 static const char*
76 ssl_error_string[] =
77 {
78  "No error",
79  "Unable to get certificate",
80  "Unable to get private key",
81  "Private key does not match the certificate public key"
82  "SSL_CTX_set_default_verify_paths failed",
83  "Failed to set ciphers to use",
84  "SSL_CTX_new failed"
85 };
86 
87 const char*
88 sslGetErrString(enum enum_ssl_init_error e)
89 {
90  DBUG_ASSERT(SSL_INITERR_NOERROR < e && e < SSL_INITERR_LASTERR);
91  return ssl_error_string[e];
92 }
93 
94 static int
95 vio_set_cert_stuff(SSL_CTX *ctx, const char *cert_file, const char *key_file,
96  enum enum_ssl_init_error* error)
97 {
98  DBUG_ENTER("vio_set_cert_stuff");
99  DBUG_PRINT("enter", ("ctx: 0x%lx cert_file: %s key_file: %s",
100  (long) ctx, cert_file, key_file));
101 
102  if (!cert_file && key_file)
103  cert_file= key_file;
104 
105  if (!key_file && cert_file)
106  key_file= cert_file;
107 
108  if (cert_file &&
109  SSL_CTX_use_certificate_file(ctx, cert_file, SSL_FILETYPE_PEM) <= 0)
110  {
111  *error= SSL_INITERR_CERT;
112  DBUG_PRINT("error",("%s from file '%s'", sslGetErrString(*error), cert_file));
113  DBUG_EXECUTE("error", ERR_print_errors_fp(DBUG_FILE););
114  fprintf(stderr, "SSL error: %s from '%s'\n", sslGetErrString(*error),
115  cert_file);
116  fflush(stderr);
117  DBUG_RETURN(1);
118  }
119 
120  if (key_file &&
121  SSL_CTX_use_PrivateKey_file(ctx, key_file, SSL_FILETYPE_PEM) <= 0)
122  {
123  *error= SSL_INITERR_KEY;
124  DBUG_PRINT("error", ("%s from file '%s'", sslGetErrString(*error), key_file));
125  DBUG_EXECUTE("error", ERR_print_errors_fp(DBUG_FILE););
126  fprintf(stderr, "SSL error: %s from '%s'\n", sslGetErrString(*error),
127  key_file);
128  fflush(stderr);
129  DBUG_RETURN(1);
130  }
131 
132  /*
133  If we are using DSA, we can copy the parameters from the private key
134  Now we know that a key and cert have been set against the SSL context
135  */
136  if (cert_file && !SSL_CTX_check_private_key(ctx))
137  {
138  *error= SSL_INITERR_NOMATCH;
139  DBUG_PRINT("error", ("%s",sslGetErrString(*error)));
140  DBUG_EXECUTE("error", ERR_print_errors_fp(DBUG_FILE););
141  fprintf(stderr, "SSL error: %s\n", sslGetErrString(*error));
142  fflush(stderr);
143  DBUG_RETURN(1);
144  }
145 
146  DBUG_RETURN(0);
147 }
148 
149 
150 void ssl_start()
151 {
152  if (!ssl_algorithms_added)
153  {
154  ssl_algorithms_added= TRUE;
155  SSL_library_init();
156  OpenSSL_add_all_algorithms();
157 
158  }
159 
160  if (!ssl_error_strings_loaded)
161  {
162  ssl_error_strings_loaded= TRUE;
163  SSL_load_error_strings();
164  }
165 }
166 
167 /************************ VioSSLFd **********************************/
168 static struct st_VioSSLFd *
169 new_VioSSLFd(const char *key_file, const char *cert_file,
170  const char *ca_file, const char *ca_path,
171  const char *cipher, my_bool is_client,
172  enum enum_ssl_init_error *error,
173  const char *crl_file, const char *crl_path)
174 {
175  DH *dh;
176  struct st_VioSSLFd *ssl_fd;
177  DBUG_ENTER("new_VioSSLFd");
178  DBUG_PRINT("enter",
179  ("key_file: '%s' cert_file: '%s' ca_file: '%s' ca_path: '%s' "
180  "cipher: '%s' crl_file: '%s' crl_path: '%s' ",
181  key_file ? key_file : "NULL",
182  cert_file ? cert_file : "NULL",
183  ca_file ? ca_file : "NULL",
184  ca_path ? ca_path : "NULL",
185  cipher ? cipher : "NULL",
186  crl_file ? crl_file : "NULL",
187  crl_path ? crl_path : "NULL"));
188 
189  ssl_start();
190 
191  if (!(ssl_fd= ((struct st_VioSSLFd*)
192  my_malloc(sizeof(struct st_VioSSLFd),MYF(0)))))
193  DBUG_RETURN(0);
194 
195  if (!(ssl_fd->ssl_context= SSL_CTX_new(is_client ?
196  TLSv1_client_method() :
197  TLSv1_server_method())))
198  {
199  *error= SSL_INITERR_MEMFAIL;
200  DBUG_PRINT("error", ("%s", sslGetErrString(*error)));
201  report_errors();
202  my_free(ssl_fd);
203  DBUG_RETURN(0);
204  }
205 
206  /*
207  Set the ciphers that can be used
208  NOTE: SSL_CTX_set_cipher_list will return 0 if
209  none of the provided ciphers could be selected
210  */
211  if (cipher &&
212  SSL_CTX_set_cipher_list(ssl_fd->ssl_context, cipher) == 0)
213  {
214  *error= SSL_INITERR_CIPHERS;
215  DBUG_PRINT("error", ("%s", sslGetErrString(*error)));
216  report_errors();
217  SSL_CTX_free(ssl_fd->ssl_context);
218  my_free(ssl_fd);
219  DBUG_RETURN(0);
220  }
221 
222  /* Load certs from the trusted ca */
223  if (SSL_CTX_load_verify_locations(ssl_fd->ssl_context, ca_file, ca_path) == 0)
224  {
225  DBUG_PRINT("warning", ("SSL_CTX_load_verify_locations failed"));
226  if (ca_file || ca_path)
227  {
228  /* fail only if ca file or ca path were supplied and looking into
229  them fails. */
230  *error= SSL_INITERR_BAD_PATHS;
231  DBUG_PRINT("error", ("SSL_CTX_load_verify_locations failed : %s",
232  sslGetErrString(*error)));
233  report_errors();
234  SSL_CTX_free(ssl_fd->ssl_context);
235  my_free(ssl_fd);
236  DBUG_RETURN(0);
237  }
238 
239  /* otherwise go use the defaults */
240  if (SSL_CTX_set_default_verify_paths(ssl_fd->ssl_context) == 0)
241  {
242  *error= SSL_INITERR_BAD_PATHS;
243  DBUG_PRINT("error", ("%s", sslGetErrString(*error)));
244  report_errors();
245  SSL_CTX_free(ssl_fd->ssl_context);
246  my_free(ssl_fd);
247  DBUG_RETURN(0);
248  }
249  }
250 
251  if (crl_file || crl_path)
252  {
253 #ifdef HAVE_YASSL
254  DBUG_PRINT("warning", ("yaSSL doesn't support CRL"));
255  DBUG_ASSERT(0);
256 #else
257  X509_STORE *store= SSL_CTX_get_cert_store(ssl_fd->ssl_context);
258  /* Load crls from the trusted ca */
259  if (X509_STORE_load_locations(store, crl_file, crl_path) == 0 ||
260  X509_STORE_set_flags(store,
261  X509_V_FLAG_CRL_CHECK |
262  X509_V_FLAG_CRL_CHECK_ALL) == 0)
263  {
264  DBUG_PRINT("warning", ("X509_STORE_load_locations for CRL failed"));
265  *error= SSL_INITERR_BAD_PATHS;
266  DBUG_PRINT("error", ("%s", sslGetErrString(*error)));
267  report_errors();
268  SSL_CTX_free(ssl_fd->ssl_context);
269  my_free(ssl_fd);
270  DBUG_RETURN(0);
271  }
272 #endif
273  }
274 
275  if (vio_set_cert_stuff(ssl_fd->ssl_context, cert_file, key_file, error))
276  {
277  DBUG_PRINT("error", ("vio_set_cert_stuff failed"));
278  report_errors();
279  SSL_CTX_free(ssl_fd->ssl_context);
280  my_free(ssl_fd);
281  DBUG_RETURN(0);
282  }
283 
284  /* DH stuff */
285  dh=get_dh512();
286  SSL_CTX_set_tmp_dh(ssl_fd->ssl_context, dh);
287  DH_free(dh);
288 
289  DBUG_PRINT("exit", ("OK 1"));
290 
291  DBUG_RETURN(ssl_fd);
292 }
293 
294 
295 /************************ VioSSLConnectorFd **********************************/
296 struct st_VioSSLFd *
297 new_VioSSLConnectorFd(const char *key_file, const char *cert_file,
298  const char *ca_file, const char *ca_path,
299  const char *cipher, enum enum_ssl_init_error* error,
300  const char *crl_file, const char *crl_path)
301 {
302  struct st_VioSSLFd *ssl_fd;
303  int verify= SSL_VERIFY_PEER;
304 
305  /*
306  Turn off verification of servers certificate if both
307  ca_file and ca_path is set to NULL
308  */
309  if (ca_file == 0 && ca_path == 0)
310  verify= SSL_VERIFY_NONE;
311 
312  if (!(ssl_fd= new_VioSSLFd(key_file, cert_file, ca_file,
313  ca_path, cipher, TRUE, error,
314  crl_file, crl_path)))
315  {
316  return 0;
317  }
318 
319  /* Init the VioSSLFd as a "connector" ie. the client side */
320 
321  SSL_CTX_set_verify(ssl_fd->ssl_context, verify, NULL);
322 
323  return ssl_fd;
324 }
325 
326 
327 /************************ VioSSLAcceptorFd **********************************/
328 struct st_VioSSLFd *
329 new_VioSSLAcceptorFd(const char *key_file, const char *cert_file,
330  const char *ca_file, const char *ca_path,
331  const char *cipher, enum enum_ssl_init_error* error,
332  const char *crl_file, const char *crl_path)
333 {
334  struct st_VioSSLFd *ssl_fd;
335  int verify= SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE;
336  if (!(ssl_fd= new_VioSSLFd(key_file, cert_file, ca_file,
337  ca_path, cipher, FALSE, error,
338  crl_file, crl_path)))
339  {
340  return 0;
341  }
342  /* Init the the VioSSLFd as a "acceptor" ie. the server side */
343 
344  /* Set max number of cached sessions, returns the previous size */
345  SSL_CTX_sess_set_cache_size(ssl_fd->ssl_context, 128);
346 
347  SSL_CTX_set_verify(ssl_fd->ssl_context, verify, NULL);
348 
349  /*
350  Set session_id - an identifier for this server session
351  Use the ssl_fd pointer
352  */
353  SSL_CTX_set_session_id_context(ssl_fd->ssl_context,
354  (const unsigned char *)ssl_fd,
355  sizeof(ssl_fd));
356 
357  return ssl_fd;
358 }
359 
360 void free_vio_ssl_acceptor_fd(struct st_VioSSLFd *fd)
361 {
362  SSL_CTX_free(fd->ssl_context);
363  my_free(fd);
364 }
365 #endif /* HAVE_OPENSSL */