1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at http://curl.haxx.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ***************************************************************************/
22
23#include "setup.h"
24
25#ifdef USE_QSOSSL
26
27#include <qsossl.h>
28
29#ifdef HAVE_LIMITS_H
30#  include <limits.h>
31#endif
32
33#include <curl/curl.h>
34#include "urldata.h"
35#include "sendf.h"
36#include "qssl.h"
37#include "sslgen.h"
38#include "connect.h" /* for the connect timeout */
39#include "select.h"
40#include "curl_memory.h"
41/* The last #include file should be: */
42#include "memdebug.h"
43
44
45int Curl_qsossl_init(void)
46
47{
48  /* Nothing to do here. We must have connection data to initialize ssl, so
49   * defer.
50   */
51
52  return 1;
53}
54
55
56void Curl_qsossl_cleanup(void)
57
58{
59  /* Nothing to do. */
60}
61
62
63static CURLcode Curl_qsossl_init_session(struct SessionHandle * data)
64
65{
66  int rc;
67  char * certname;
68  SSLInit initstr;
69  SSLInitApp initappstr;
70
71  /* Initialize the job for SSL according to the current parameters.
72   * QsoSSL offers two ways to do it: SSL_Init_Application() that uses an
73   *  application identifier to select certificates in the main certificate
74   *  store, and SSL_Init() that uses named keyring files and a password.
75   * It is not possible to have different keyrings for the CAs and the
76   *  local certificate. We thus use the certificate name to identify the
77   *  keyring if given, else the CA file name.
78   * If the key file name is given, it is taken as the password for the
79   *  keyring in certificate file.
80   * We first try to SSL_Init_Application(), then SSL_Init() if it failed.
81   */
82
83  certname = data->set.str[STRING_CERT];
84
85  if(!certname) {
86    certname = data->set.str[STRING_SSL_CAFILE];
87
88    if(!certname)
89      return CURLE_OK;          /* Use previous setup. */
90    }
91
92  memset((char *) &initappstr, 0, sizeof initappstr);
93  initappstr.applicationID = certname;
94  initappstr.applicationIDLen = strlen(certname);
95  initappstr.protocol = SSL_VERSION_CURRENT;    /* TLSV1 compat. SSLV[23]. */
96  initappstr.sessionType = SSL_REGISTERED_AS_CLIENT;
97  rc = SSL_Init_Application(&initappstr);
98
99  if(rc == SSL_ERROR_NOT_REGISTERED) {
100    initstr.keyringFileName = certname;
101    initstr.keyringPassword = data->set.str[STRING_KEY];
102    initstr.cipherSuiteList = NULL;    /* Use default. */
103    initstr.cipherSuiteListLen = 0;
104    rc = SSL_Init(&initstr);
105    }
106
107  switch (rc) {
108
109  case 0:                             /* No error. */
110    break;
111
112  case SSL_ERROR_IO:
113    failf(data, "SSL_Init() I/O error: %s", strerror(errno));
114    return CURLE_SSL_CONNECT_ERROR;
115
116  case SSL_ERROR_BAD_CIPHER_SUITE:
117    return CURLE_SSL_CIPHER;
118
119  case SSL_ERROR_KEYPASSWORD_EXPIRED:
120  case SSL_ERROR_NOT_REGISTERED:
121    return CURLE_SSL_CONNECT_ERROR;
122
123  case SSL_ERROR_NO_KEYRING:
124    return CURLE_SSL_CACERT;
125
126  case SSL_ERROR_CERT_EXPIRED:
127    return CURLE_SSL_CERTPROBLEM;
128
129  default:
130    failf(data, "SSL_Init(): %s", SSL_Strerror(rc, NULL));
131    return CURLE_SSL_CONNECT_ERROR;
132  }
133
134  return CURLE_OK;
135}
136
137
138static CURLcode Curl_qsossl_create(struct connectdata * conn, int sockindex)
139
140{
141  SSLHandle * h;
142  struct ssl_connect_data * connssl = &conn->ssl[sockindex];
143
144  h = SSL_Create(conn->sock[sockindex], SSL_ENCRYPT);
145
146  if(!h) {
147    failf(conn->data, "SSL_Create() I/O error: %s", strerror(errno));
148    return CURLE_SSL_CONNECT_ERROR;
149  }
150
151  connssl->handle = h;
152  return CURLE_OK;
153}
154
155
156static int Curl_qsossl_trap_cert(SSLHandle * h)
157
158{
159  return 1;       /* Accept certificate. */
160}
161
162
163static CURLcode Curl_qsossl_handshake(struct connectdata * conn, int sockindex)
164
165{
166  int rc;
167  struct SessionHandle * data = conn->data;
168  struct ssl_connect_data * connssl = &conn->ssl[sockindex];
169  SSLHandle * h = connssl->handle;
170  long timeout_ms;
171
172  h->exitPgm = NULL;
173
174  if(!data->set.ssl.verifyhost)
175    h->exitPgm = Curl_qsossl_trap_cert;
176
177  /* figure out how long time we should wait at maximum */
178  timeout_ms = Curl_timeleft(data, NULL, TRUE);
179
180  if(timeout_ms < 0) {
181    /* time-out, bail out, go home */
182    failf(data, "Connection time-out");
183    return CURLE_OPERATION_TIMEDOUT;
184  }
185
186  /* SSL_Handshake() timeout resolution is second, so round up. */
187  h->timeout = (timeout_ms + 1000 - 1) / 1000;
188
189  /* Set-up protocol. */
190
191  switch (data->set.ssl.version) {
192
193  default:
194  case CURL_SSLVERSION_DEFAULT:
195    h->protocol = SSL_VERSION_CURRENT;          /* TLSV1 compat. SSLV[23]. */
196    break;
197
198  case CURL_SSLVERSION_TLSv1:
199    h->protocol = TLS_VERSION_1;
200    break;
201
202  case CURL_SSLVERSION_SSLv2:
203    h->protocol = SSL_VERSION_2;
204    break;
205
206  case CURL_SSLVERSION_SSLv3:
207    h->protocol = SSL_VERSION_3;
208    break;
209  }
210
211  rc = SSL_Handshake(h, SSL_HANDSHAKE_AS_CLIENT);
212
213  switch (rc) {
214
215  case 0:                             /* No error. */
216    break;
217
218  case SSL_ERROR_BAD_CERTIFICATE:
219  case SSL_ERROR_BAD_CERT_SIG:
220  case SSL_ERROR_NOT_TRUSTED_ROOT:
221    return CURLE_PEER_FAILED_VERIFICATION;
222
223  case SSL_ERROR_BAD_CIPHER_SUITE:
224  case SSL_ERROR_NO_CIPHERS:
225    return CURLE_SSL_CIPHER;
226
227  case SSL_ERROR_CERTIFICATE_REJECTED:
228  case SSL_ERROR_CERT_EXPIRED:
229  case SSL_ERROR_NO_CERTIFICATE:
230    return CURLE_SSL_CERTPROBLEM;
231
232  case SSL_ERROR_IO:
233    failf(data, "SSL_Handshake() I/O error: %s", strerror(errno));
234    return CURLE_SSL_CONNECT_ERROR;
235
236  default:
237    failf(data, "SSL_Handshake(): %s", SSL_Strerror(rc, NULL));
238    return CURLE_SSL_CONNECT_ERROR;
239  }
240
241  return CURLE_OK;
242}
243
244
245static Curl_recv qsossl_recv;
246static Curl_send qsossl_send;
247
248CURLcode Curl_qsossl_connect(struct connectdata * conn, int sockindex)
249
250{
251  struct SessionHandle * data = conn->data;
252  struct ssl_connect_data * connssl = &conn->ssl[sockindex];
253  int rc;
254
255  rc = Curl_qsossl_init_session(data);
256
257  if(rc == CURLE_OK) {
258    rc = Curl_qsossl_create(conn, sockindex);
259
260    if(rc == CURLE_OK)
261      rc = Curl_qsossl_handshake(conn, sockindex);
262    else {
263      SSL_Destroy(connssl->handle);
264      connssl->handle = NULL;
265      connssl->use = FALSE;
266      connssl->state = ssl_connection_none;
267    }
268  }
269  if(rc == CURLE_OK) {
270    connssl->state = ssl_connection_complete;
271    conn->recv[sockindex] = qsossl_recv;
272    conn->send[sockindex] = qsossl_send;
273  }
274
275  return rc;
276}
277
278
279static int Curl_qsossl_close_one(struct ssl_connect_data * conn,
280                                 struct SessionHandle * data)
281
282{
283  int rc;
284
285  if(!conn->handle)
286    return 0;
287
288  rc = SSL_Destroy(conn->handle);
289
290  if(rc) {
291    if(rc == SSL_ERROR_IO) {
292      failf(data, "SSL_Destroy() I/O error: %s", strerror(errno));
293      return -1;
294    }
295
296    /* An SSL error. */
297    failf(data, "SSL_Destroy() returned error %s", SSL_Strerror(rc, NULL));
298    return -1;
299  }
300
301  conn->handle = NULL;
302  return 0;
303}
304
305
306void Curl_qsossl_close(struct connectdata *conn, int sockindex)
307
308{
309  struct SessionHandle *data = conn->data;
310  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
311
312  if(connssl->use)
313    (void) Curl_qsossl_close_one(connssl, data);
314}
315
316
317int Curl_qsossl_close_all(struct SessionHandle * data)
318
319{
320  /* Unimplemented. */
321  (void) data;
322  return 0;
323}
324
325
326int Curl_qsossl_shutdown(struct connectdata * conn, int sockindex)
327
328{
329  struct ssl_connect_data * connssl = &conn->ssl[sockindex];
330  struct SessionHandle *data = conn->data;
331  ssize_t nread;
332  int what;
333  int rc;
334  char buf[120];
335
336  if(!connssl->handle)
337    return 0;
338
339  if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
340    return 0;
341
342  if(Curl_qsossl_close_one(connssl, data))
343    return -1;
344
345  rc = 0;
346
347  what = Curl_socket_ready(conn->sock[sockindex],
348                           CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
349
350  for(;;) {
351    if(what < 0) {
352      /* anything that gets here is fatally bad */
353      failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
354      rc = -1;
355      break;
356    }
357
358    if(!what) {                                /* timeout */
359      failf(data, "SSL shutdown timeout");
360      break;
361    }
362
363    /* Something to read, let's do it and hope that it is the close
364       notify alert from the server. No way to SSL_Read now, so use read(). */
365
366    nread = read(conn->sock[sockindex], buf, sizeof(buf));
367
368    if(nread < 0) {
369      failf(data, "read: %s", strerror(errno));
370      rc = -1;
371    }
372
373    if(nread <= 0)
374      break;
375
376    what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0);
377  }
378
379  return rc;
380}
381
382
383static ssize_t qsossl_send(struct connectdata * conn, int sockindex,
384                           const void * mem, size_t len, CURLcode * curlcode)
385
386{
387  /* SSL_Write() is said to return 'int' while write() and send() returns
388     'size_t' */
389  int rc;
390
391  rc = SSL_Write(conn->ssl[sockindex].handle, (void *) mem, (int) len);
392
393  if(rc < 0) {
394    switch(rc) {
395
396    case SSL_ERROR_BAD_STATE:
397      /* The operation did not complete; the same SSL I/O function
398         should be called again later. This is basically an EWOULDBLOCK
399         equivalent. */
400      *curlcode = CURLE_AGAIN;
401      return -1;
402
403    case SSL_ERROR_IO:
404      switch (errno) {
405      case EWOULDBLOCK:
406      case EINTR:
407        *curlcode = CURLE_AGAIN;
408        return -1;
409        }
410
411      failf(conn->data, "SSL_Write() I/O error: %s", strerror(errno));
412      *curlcode = CURLE_SEND_ERROR;
413      return -1;
414    }
415
416    /* An SSL error. */
417    failf(conn->data, "SSL_Write() returned error %s",
418          SSL_Strerror(rc, NULL));
419    *curlcode = CURLE_SEND_ERROR;
420    return -1;
421  }
422
423  return (ssize_t) rc; /* number of bytes */
424}
425
426
427static ssize_t qsossl_recv(struct connectdata * conn, int num, char * buf,
428                           size_t buffersize, CURLcode * curlcode)
429
430{
431  char error_buffer[120]; /* OpenSSL documents that this must be at
432                             least 120 bytes long. */
433  unsigned long sslerror;
434  int buffsize;
435  int nread;
436
437  buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
438  nread = SSL_Read(conn->ssl[num].handle, buf, buffsize);
439
440  if(nread < 0) {
441    /* failed SSL_read */
442
443    switch (nread) {
444
445    case SSL_ERROR_BAD_STATE:
446      /* there's data pending, re-invoke SSL_Read(). */
447      *curlcode = CURLE_AGAIN;
448      return -1;
449
450    case SSL_ERROR_IO:
451      switch (errno) {
452      case EWOULDBLOCK:
453        *curlcode = CURLE_AGAIN;
454        return -1;
455        }
456
457      failf(conn->data, "SSL_Read() I/O error: %s", strerror(errno));
458      *curlcode = CURLE_RECV_ERROR;
459      return -1;
460
461    default:
462      failf(conn->data, "SSL read error: %s", SSL_Strerror(nread, NULL));
463      *curlcode = CURLE_RECV_ERROR;
464      return -1;
465    }
466  }
467  return (ssize_t) nread;
468}
469
470
471size_t Curl_qsossl_version(char * buffer, size_t size)
472
473{
474  strncpy(buffer, "IBM OS/400 SSL", size);
475  return strlen(buffer);
476}
477
478
479int Curl_qsossl_check_cxn(struct connectdata * cxn)
480
481{
482  int err;
483  int errlen;
484
485  /* The only thing that can be tested here is at the socket level. */
486
487  if(!cxn->ssl[FIRSTSOCKET].handle)
488    return 0; /* connection has been closed */
489
490  err = 0;
491  errlen = sizeof err;
492
493  if(getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR,
494                 (unsigned char *) &err, &errlen) ||
495      errlen != sizeof err || err)
496    return 0; /* connection has been closed */
497
498  return -1;  /* connection status unknown */
499}
500
501#endif /* USE_QSOSSL */
502