viossl.c 7.49 KB
Newer Older
unknown's avatar
unknown committed
1 2 3 4 5 6 7 8
/* Copyright (C) 2000 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
9
   but WITHOUT ANY WARRANTY; without even the implied warranty of
unknown's avatar
unknown committed
10 11 12 13 14 15
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
16 17 18 19 20 21 22 23

/*
  Note that we can't have assertion on file descriptors;  The reason for
  this is that during mysql shutdown, another thread can close a file
  we are working on.  In this case we should just return read errors from
  the file descriptior.
*/

24
#include "vio_priv.h"
25 26 27

#ifdef HAVE_OPENSSL

unknown's avatar
unknown committed
28
#ifdef __NETWARE__
29 30 31 32

/* yaSSL already uses BSD sockets */
#ifndef HAVE_YASSL

unknown's avatar
unknown committed
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
/*
  The default OpenSSL implementation on NetWare uses WinSock.
  This code allows us to use the BSD sockets.
*/

static int SSL_set_fd_bsd(SSL *s, int fd)
{
  int result= -1;
  BIO_METHOD *BIO_s_bsdsocket();
  BIO *bio;

  if ((bio= BIO_new(BIO_s_bsdsocket())))
  {
    result= BIO_set_fd(bio, fd, BIO_NOCLOSE);
    SSL_set_bio(s, bio, bio);
  }
  return result;
}

#define SSL_set_fd(A, B)  SSL_set_fd_bsd((A), (B))

54
#endif /* HAVE_YASSL */
unknown's avatar
unknown committed
55 56 57
#endif /* __NETWARE__ */


unknown's avatar
unknown committed
58
static void
59
report_errors(SSL* ssl)
unknown's avatar
unknown committed
60 61
{
  unsigned long	l;
unknown's avatar
unknown committed
62 63
  const char *file;
  const char *data;
unknown's avatar
unknown committed
64 65
  int line, flags;
#ifndef DBUG_OFF
66
  char buf[512];
unknown's avatar
unknown committed
67
#endif
68

unknown's avatar
unknown committed
69 70
  DBUG_ENTER("report_errors");

unknown's avatar
unknown committed
71
  while ((l= ERR_get_error_line_data(&file,&line,&data,&flags)))
unknown's avatar
unknown committed
72 73 74 75
  {
    DBUG_PRINT("error", ("OpenSSL: %s:%s:%d:%s\n", ERR_error_string(l,buf),
			 file,line,(flags&ERR_TXT_STRING)?data:"")) ;
  }
76 77

  if (ssl)
unknown's avatar
unknown committed
78 79 80 81
    DBUG_PRINT("error", ("error: %s",
                         ERR_error_string(SSL_get_error(ssl, l), buf)));

  DBUG_PRINT("info", ("socket_errno: %d", socket_errno));
unknown's avatar
unknown committed
82 83 84
  DBUG_VOID_RETURN;
}

85

unknown's avatar
unknown committed
86
int vio_ssl_read(Vio *vio, gptr buf, int size)
87 88 89
{
  int r;
  DBUG_ENTER("vio_ssl_read");
unknown's avatar
unknown committed
90
  DBUG_PRINT("enter", ("sd: %d, buf: 0x%lx, size: %d, ssl_: 0x%lx",
91
		       vio->sd, buf, size, vio->ssl_arg));
92

unknown's avatar
unknown committed
93 94 95
  r= SSL_read((SSL*) vio->ssl_arg, buf, size);
#ifndef DBUG_OFF
  if (r < 0)
96
    report_errors((SSL*) vio->ssl_arg);
unknown's avatar
unknown committed
97
#endif
98 99 100 101 102
  DBUG_PRINT("exit", ("%d", r));
  DBUG_RETURN(r);
}


unknown's avatar
unknown committed
103
int vio_ssl_write(Vio *vio, const gptr buf, int size)
104 105 106
{
  int r;
  DBUG_ENTER("vio_ssl_write");
unknown's avatar
unknown committed
107
  DBUG_PRINT("enter", ("sd: %d, buf: 0x%lx, size: %d", vio->sd, buf, size));
unknown's avatar
unknown committed
108

unknown's avatar
unknown committed
109 110 111
  r= SSL_write((SSL*) vio->ssl_arg, buf, size);
#ifndef DBUG_OFF
  if (r < 0)
112
    report_errors((SSL*) vio->ssl_arg);
unknown's avatar
unknown committed
113
#endif
114 115 116 117 118
  DBUG_PRINT("exit", ("%d", r));
  DBUG_RETURN(r);
}


unknown's avatar
unknown committed
119
int vio_ssl_close(Vio *vio)
120
{
unknown's avatar
unknown committed
121
  int r= 0;
unknown's avatar
unknown committed
122
  SSL *ssl= (SSL*)vio->ssl_arg;
123 124
  DBUG_ENTER("vio_ssl_close");

unknown's avatar
unknown committed
125
  if (ssl)
126
  {
unknown's avatar
unknown committed
127
    switch ((r= SSL_shutdown(ssl)))
128
    {
unknown's avatar
unknown committed
129 130 131 132 133 134 135 136 137 138
    case 1: /* Shutdown successful */
      break;
    case 0: /* Shutdown not yet finished, call it again */
      if ((r= SSL_shutdown(ssl) >= 0))
        break;
      /* Fallthrough */
    default: /* Shutdown failed */
      DBUG_PRINT("vio_error", ("SSL_shutdown() failed, error: %s",
                               SSL_get_error(ssl, r)));
      break;
139
    }
unknown's avatar
unknown committed
140 141
    SSL_free(ssl);
    vio->ssl_arg= 0;
142
  }
unknown's avatar
unknown committed
143
  DBUG_RETURN(vio_close(vio));
144 145 146
}


unknown's avatar
unknown committed
147
int sslaccept(struct st_VioSSLFd *ptr, Vio *vio, long timeout)
148
{
unknown's avatar
unknown committed
149
  SSL *ssl;
150
  my_bool unused;
unknown's avatar
unknown committed
151
  my_bool net_blocking;
152
  enum enum_vio_type old_type;
153
  DBUG_ENTER("sslaccept");
unknown's avatar
unknown committed
154
  DBUG_PRINT("enter", ("sd: %d  ptr: %p, timeout: %d",
155
                       vio->sd, ptr, timeout));
156

unknown's avatar
unknown committed
157
  old_type= vio->type;
unknown's avatar
unknown committed
158
  net_blocking= vio_is_blocking(vio);
159
  vio_blocking(vio, 1, &unused);	/* Must be called before reset */
unknown's avatar
unknown committed
160 161 162
  vio_reset(vio, VIO_TYPE_SSL, vio->sd, 0, FALSE);

  if (!(ssl= SSL_new(ptr->ssl_context)))
163 164
  {
    DBUG_PRINT("error", ("SSL_new failure"));
165
    report_errors(ssl);
unknown's avatar
unknown committed
166 167 168
    vio_reset(vio, old_type,vio->sd,0,FALSE);
    vio_blocking(vio, net_blocking, &unused);
    DBUG_RETURN(1);
169
  }
unknown's avatar
unknown committed
170 171 172 173 174
  vio->ssl_arg= (void*)ssl;
  DBUG_PRINT("info", ("ssl_: %p  timeout: %ld", ssl, timeout));
  SSL_clear(ssl);
  SSL_SESSION_set_timeout(SSL_get_session(ssl), timeout);
  SSL_set_fd(ssl, vio->sd);
175
  if (SSL_accept(ssl) < 1)
unknown's avatar
unknown committed
176
  {
177
    DBUG_PRINT("error", ("SSL_accept failure"));
178
    report_errors(ssl);
unknown's avatar
unknown committed
179
    SSL_free(ssl);
180
    vio->ssl_arg= 0;
unknown's avatar
unknown committed
181 182 183 184
    vio_reset(vio, old_type,vio->sd,0,FALSE);
    vio_blocking(vio, net_blocking, &unused);
    DBUG_RETURN(1);
  }
unknown's avatar
unknown committed
185

unknown's avatar
unknown committed
186
#ifndef DBUG_OFF
187
  {
unknown's avatar
unknown committed
188
    char buf[1024];
unknown's avatar
unknown committed
189
    X509 *client_cert;
unknown's avatar
unknown committed
190
    DBUG_PRINT("info",("cipher_name= '%s'", SSL_get_cipher_name(ssl)));
191

unknown's avatar
unknown committed
192 193 194 195 196 197
    if ((client_cert= SSL_get_peer_certificate (ssl)))
    {
      DBUG_PRINT("info",("Client certificate:"));
      X509_NAME_oneline (X509_get_subject_name (client_cert),
                         buf, sizeof(buf));
      DBUG_PRINT("info",("\t subject: %s", buf));
198

unknown's avatar
unknown committed
199 200 201
      X509_NAME_oneline (X509_get_issuer_name  (client_cert),
                         buf, sizeof(buf));
      DBUG_PRINT("info",("\t issuer: %s", buf));
unknown's avatar
unknown committed
202

unknown's avatar
unknown committed
203 204 205 206
      X509_free (client_cert);
    }
    else
      DBUG_PRINT("info",("Client does not have certificate."));
207

unknown's avatar
unknown committed
208 209 210 211 212 213 214
    if (SSL_get_shared_ciphers(ssl, buf, sizeof(buf)))
    {
      DBUG_PRINT("info",("shared_ciphers: '%s'", buf));
    }
    else
      DBUG_PRINT("info",("no shared ciphers!"));
  }
unknown's avatar
unknown committed
215
#endif
unknown's avatar
unknown committed
216

unknown's avatar
unknown committed
217
  DBUG_RETURN(0);
218 219
}

220

unknown's avatar
unknown committed
221
int sslconnect(struct st_VioSSLFd *ptr, Vio *vio, long timeout)
222
{
unknown's avatar
unknown committed
223
  SSL *ssl;
224
  my_bool unused;
unknown's avatar
unknown committed
225
  my_bool net_blocking;
unknown's avatar
unknown committed
226 227
  enum enum_vio_type old_type;

228
  DBUG_ENTER("sslconnect");
unknown's avatar
unknown committed
229 230
  DBUG_PRINT("enter", ("sd: %d,  ptr: %p, ctx: %p",
                       vio->sd, ptr, ptr->ssl_context));
231

unknown's avatar
unknown committed
232
  old_type= vio->type;
unknown's avatar
unknown committed
233
  net_blocking= vio_is_blocking(vio);
234
  vio_blocking(vio, 1, &unused);	/* Must be called before reset */
unknown's avatar
unknown committed
235 236
  vio_reset(vio, VIO_TYPE_SSL, vio->sd, 0, FALSE);
  if (!(ssl= SSL_new(ptr->ssl_context)))
237 238
  {
    DBUG_PRINT("error", ("SSL_new failure"));
239
    report_errors(ssl);
unknown's avatar
unknown committed
240 241
    vio_reset(vio, old_type, vio->sd, 0, FALSE);
    vio_blocking(vio, net_blocking, &unused);
242
    DBUG_RETURN(1);
243
  }
unknown's avatar
unknown committed
244 245 246 247 248
  vio->ssl_arg= (void*)ssl;
  DBUG_PRINT("info", ("ssl: %p, timeout: %ld", ssl, timeout));
  SSL_clear(ssl);
  SSL_SESSION_set_timeout(SSL_get_session(ssl), timeout);
  SSL_set_fd(ssl, vio->sd);
249
  if (SSL_connect(ssl) < 1)
unknown's avatar
unknown committed
250
  {
251
    DBUG_PRINT("error", ("SSL_connect failure"));
252
    report_errors(ssl);
unknown's avatar
unknown committed
253
    SSL_free(ssl);
254
    vio->ssl_arg= 0;
unknown's avatar
unknown committed
255
    vio_reset(vio, old_type, vio->sd, 0, FALSE);
unknown's avatar
unknown committed
256 257
    vio_blocking(vio, net_blocking, &unused);
    DBUG_RETURN(1);
unknown's avatar
unknown committed
258
  }
unknown's avatar
unknown committed
259
#ifndef DBUG_OFF
260
  {
unknown's avatar
unknown committed
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
    X509 *server_cert;
    DBUG_PRINT("info",("cipher_name: '%s'" , SSL_get_cipher_name(ssl)));

    if ((server_cert= SSL_get_peer_certificate (ssl)))
    {
      char buf[256];
      DBUG_PRINT("info",("Server certificate:"));
      X509_NAME_oneline(X509_get_subject_name(server_cert), buf, sizeof(buf));
      DBUG_PRINT("info",("\t subject: %s", buf));
      X509_NAME_oneline (X509_get_issuer_name(server_cert), buf, sizeof(buf));
      DBUG_PRINT("info",("\t issuer: %s", buf));
      X509_free (server_cert);
    }
    else
      DBUG_PRINT("info",("Server does not have certificate."));
276
  }
unknown's avatar
unknown committed
277
#endif
unknown's avatar
unknown committed
278

279
  DBUG_RETURN(0);
280 281
}

282

unknown's avatar
unknown committed
283
int vio_ssl_blocking(Vio *vio __attribute__((unused)),
284 285 286
		     my_bool set_blocking_mode,
		     my_bool *old_mode)
{
unknown's avatar
unknown committed
287 288
  /* Mode is always blocking */
  *old_mode= 1;
289
  /* Return error if we try to change to non_blocking mode */
unknown's avatar
unknown committed
290
  return (set_blocking_mode ? 0 : 1);
291 292
}

293
#endif /* HAVE_OPENSSL */