~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

Viewing changes to vio/viossl.c

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2000 MySQL AB
 
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
/*
 
17
  Note that we can't have assertion on file descriptors;  The reason for
 
18
  this is that during mysql shutdown, another thread can close a file
 
19
  we are working on.  In this case we should just return read errors from
 
20
  the file descriptior.
 
21
*/
 
22
 
 
23
#include "vio_priv.h"
 
24
 
 
25
#ifdef HAVE_OPENSSL
 
26
 
 
27
#ifdef __NETWARE__
 
28
 
 
29
/* yaSSL already uses BSD sockets */
 
30
#ifndef HAVE_YASSL
 
31
 
 
32
/*
 
33
  The default OpenSSL implementation on NetWare uses WinSock.
 
34
  This code allows us to use the BSD sockets.
 
35
*/
 
36
 
 
37
static int SSL_set_fd_bsd(SSL *s, int fd)
 
38
{
 
39
  int result= -1;
 
40
  BIO_METHOD *BIO_s_bsdsocket();
 
41
  BIO *bio;
 
42
 
 
43
  if ((bio= BIO_new(BIO_s_bsdsocket())))
 
44
  {
 
45
    result= BIO_set_fd(bio, fd, BIO_NOCLOSE);
 
46
    SSL_set_bio(s, bio, bio);
 
47
  }
 
48
  return result;
 
49
}
 
50
 
 
51
#define SSL_set_fd(A, B)  SSL_set_fd_bsd((A), (B))
 
52
 
 
53
#endif /* HAVE_YASSL */
 
54
#endif /* __NETWARE__ */
 
55
 
 
56
 
 
57
static void
 
58
report_errors(SSL* ssl)
 
59
{
 
60
  unsigned long l;
 
61
  const char *file;
 
62
  const char *data;
 
63
  int line, flags;
 
64
#ifndef DBUG_OFF
 
65
  char buf[512];
 
66
#endif
 
67
 
 
68
  DBUG_ENTER("report_errors");
 
69
 
 
70
  while ((l= ERR_get_error_line_data(&file,&line,&data,&flags)))
 
71
  {
 
72
    DBUG_PRINT("error", ("OpenSSL: %s:%s:%d:%s\n", ERR_error_string(l,buf),
 
73
                         file,line,(flags&ERR_TXT_STRING)?data:"")) ;
 
74
  }
 
75
 
 
76
  if (ssl)
 
77
    DBUG_PRINT("error", ("error: %s",
 
78
                         ERR_error_string(SSL_get_error(ssl, l), buf)));
 
79
 
 
80
  DBUG_PRINT("info", ("socket_errno: %d", socket_errno));
 
81
  DBUG_VOID_RETURN;
 
82
}
 
83
 
 
84
 
 
85
size_t vio_ssl_read(Vio *vio, uchar* buf, size_t size)
 
86
{
 
87
  size_t r;
 
88
  DBUG_ENTER("vio_ssl_read");
 
89
  DBUG_PRINT("enter", ("sd: %d  buf: 0x%lx  size: %u  ssl: 0x%lx",
 
90
                       vio->sd, (long) buf, (uint) size, (long) vio->ssl_arg));
 
91
 
 
92
  r= SSL_read((SSL*) vio->ssl_arg, buf, size);
 
93
#ifndef DBUG_OFF
 
94
  if (r == (size_t) -1)
 
95
    report_errors((SSL*) vio->ssl_arg);
 
96
#endif
 
97
  DBUG_PRINT("exit", ("%u", (uint) r));
 
98
  DBUG_RETURN(r);
 
99
}
 
100
 
 
101
 
 
102
size_t vio_ssl_write(Vio *vio, const uchar* buf, size_t size)
 
103
{
 
104
  size_t r;
 
105
  DBUG_ENTER("vio_ssl_write");
 
106
  DBUG_PRINT("enter", ("sd: %d  buf: 0x%lx  size: %u", vio->sd,
 
107
                       (long) buf, (uint) size));
 
108
 
 
109
  r= SSL_write((SSL*) vio->ssl_arg, buf, size);
 
110
#ifndef DBUG_OFF
 
111
  if (r == (size_t) -1)
 
112
    report_errors((SSL*) vio->ssl_arg);
 
113
#endif
 
114
  DBUG_PRINT("exit", ("%u", (uint) r));
 
115
  DBUG_RETURN(r);
 
116
}
 
117
 
 
118
 
 
119
int vio_ssl_close(Vio *vio)
 
120
{
 
121
  int r= 0;
 
122
  SSL *ssl= (SSL*)vio->ssl_arg;
 
123
  DBUG_ENTER("vio_ssl_close");
 
124
 
 
125
  if (ssl)
 
126
  {
 
127
    /*
 
128
    THE SSL standard says that SSL sockets must send and receive a close_notify
 
129
    alert on socket shutdown to avoid truncation attacks. However, this can
 
130
    cause problems since we often hold a lock during shutdown and this IO can
 
131
    take an unbounded amount of time to complete. Since our packets are self
 
132
    describing with length, we aren't vunerable to these attacks. Therefore,
 
133
    we just shutdown by closing the socket (quiet shutdown).
 
134
    */
 
135
    SSL_set_quiet_shutdown(ssl, 1); 
 
136
    
 
137
    switch ((r= SSL_shutdown(ssl))) {
 
138
    case 1:
 
139
      /* Shutdown successful */
 
140
      break;
 
141
    case 0:
 
142
      /*
 
143
        Shutdown not yet finished - since the socket is going to
 
144
        be closed there is no need to call SSL_shutdown() a second
 
145
        time to wait for the other side to respond
 
146
      */
 
147
      break;
 
148
    default: /* Shutdown failed */
 
149
      DBUG_PRINT("vio_error", ("SSL_shutdown() failed, error: %d",
 
150
                               SSL_get_error(ssl, r)));
 
151
      break;
 
152
    }
 
153
  }
 
154
  DBUG_RETURN(vio_close(vio));
 
155
}
 
156
 
 
157
 
 
158
void vio_ssl_delete(Vio *vio)
 
159
{
 
160
  if (!vio)
 
161
    return; /* It must be safe to delete null pointer */
 
162
 
 
163
  if (vio->type == VIO_TYPE_SSL)
 
164
    vio_ssl_close(vio); /* Still open, close connection first */
 
165
 
 
166
  if (vio->ssl_arg)
 
167
  {
 
168
    SSL_free((SSL*) vio->ssl_arg);
 
169
    vio->ssl_arg= 0;
 
170
  }
 
171
 
 
172
  vio_delete(vio);
 
173
}
 
174
 
 
175
 
 
176
static int ssl_do(struct st_VioSSLFd *ptr, Vio *vio, long timeout,
 
177
                  int (*connect_accept_func)(SSL*))
 
178
{
 
179
  SSL *ssl;
 
180
  my_bool unused;
 
181
  my_bool was_blocking;
 
182
 
 
183
  DBUG_ENTER("ssl_do");
 
184
  DBUG_PRINT("enter", ("ptr: 0x%lx, sd: %d  ctx: 0x%lx",
 
185
                       (long) ptr, vio->sd, (long) ptr->ssl_context));
 
186
 
 
187
  /* Set socket to blocking if not already set */
 
188
  vio_blocking(vio, 1, &was_blocking);
 
189
 
 
190
  if (!(ssl= SSL_new(ptr->ssl_context)))
 
191
  {
 
192
    DBUG_PRINT("error", ("SSL_new failure"));
 
193
    report_errors(ssl);
 
194
    vio_blocking(vio, was_blocking, &unused);
 
195
    DBUG_RETURN(1);
 
196
  }
 
197
  DBUG_PRINT("info", ("ssl: 0x%lx timeout: %ld", (long) ssl, timeout));
 
198
  SSL_clear(ssl);
 
199
  SSL_SESSION_set_timeout(SSL_get_session(ssl), timeout);
 
200
  SSL_set_fd(ssl, vio->sd);
 
201
 
 
202
  if (connect_accept_func(ssl) < 1)
 
203
  {
 
204
    DBUG_PRINT("error", ("SSL_connect/accept failure"));
 
205
    report_errors(ssl);
 
206
    SSL_free(ssl);
 
207
    vio_blocking(vio, was_blocking, &unused);
 
208
    DBUG_RETURN(1);
 
209
  }
 
210
 
 
211
  /*
 
212
    Connection succeeded. Install new function handlers,
 
213
    change type, set sd to the fd used when connecting
 
214
    and set pointer to the SSL structure
 
215
  */
 
216
  vio_reset(vio, VIO_TYPE_SSL, SSL_get_fd(ssl), 0, 0);
 
217
  vio->ssl_arg= (void*)ssl;
 
218
 
 
219
#ifndef DBUG_OFF
 
220
  {
 
221
    /* Print some info about the peer */
 
222
    X509 *cert;
 
223
    char buf[512];
 
224
 
 
225
    DBUG_PRINT("info",("SSL connection succeeded"));
 
226
    DBUG_PRINT("info",("Using cipher: '%s'" , SSL_get_cipher_name(ssl)));
 
227
 
 
228
    if ((cert= SSL_get_peer_certificate (ssl)))
 
229
    {
 
230
      DBUG_PRINT("info",("Peer certificate:"));
 
231
      X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
 
232
      DBUG_PRINT("info",("\t subject: '%s'", buf));
 
233
      X509_NAME_oneline(X509_get_issuer_name(cert), buf, sizeof(buf));
 
234
      DBUG_PRINT("info",("\t issuer: '%s'", buf));
 
235
      X509_free(cert);
 
236
    }
 
237
    else
 
238
      DBUG_PRINT("info",("Peer does not have certificate."));
 
239
 
 
240
    if (SSL_get_shared_ciphers(ssl, buf, sizeof(buf)))
 
241
    {
 
242
      DBUG_PRINT("info",("shared_ciphers: '%s'", buf));
 
243
    }
 
244
    else
 
245
      DBUG_PRINT("info",("no shared ciphers!"));
 
246
  }
 
247
#endif
 
248
 
 
249
  DBUG_RETURN(0);
 
250
}
 
251
 
 
252
 
 
253
int sslaccept(struct st_VioSSLFd *ptr, Vio *vio, long timeout)
 
254
{
 
255
  DBUG_ENTER("sslaccept");
 
256
  DBUG_RETURN(ssl_do(ptr, vio, timeout, SSL_accept));
 
257
}
 
258
 
 
259
 
 
260
int sslconnect(struct st_VioSSLFd *ptr, Vio *vio, long timeout)
 
261
{
 
262
  DBUG_ENTER("sslconnect");
 
263
  DBUG_RETURN(ssl_do(ptr, vio, timeout, SSL_connect));
 
264
}
 
265
 
 
266
 
 
267
int vio_ssl_blocking(Vio *vio __attribute__((unused)),
 
268
                     my_bool set_blocking_mode,
 
269
                     my_bool *old_mode)
 
270
{
 
271
  /* Mode is always blocking */
 
272
  *old_mode= 1;
 
273
  /* Return error if we try to change to non_blocking mode */
 
274
  return (set_blocking_mode ? 0 : 1);
 
275
}
 
276
 
 
277
 
 
278
 
 
279
#endif /* HAVE_OPENSSL */