Update tag value for tizen 2.0 build
[external/curl.git] / lib / qssl.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2010, 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 #include <qsossl.h>
27 #include <errno.h>
28 #include <string.h>
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
45 int 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
56 void Curl_qsossl_cleanup(void)
57
58 {
59   /* Nothing to do. */
60 }
61
62
63 static 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
138 static 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
156 static int Curl_qsossl_trap_cert(SSLHandle * h)
157
158 {
159   return 1;       /* Accept certificate. */
160 }
161
162
163 static 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(conn, 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
245 static Curl_recv qsossl_recv;
246 static Curl_send qsossl_send;
247
248 CURLcode 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
279 static 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
306 void 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
317 int Curl_qsossl_close_all(struct SessionHandle * data)
318
319 {
320   /* Unimplemented. */
321   (void) data;
322   return 0;
323 }
324
325
326 int 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
383 static 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 basicly 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
427 static 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
471 size_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
479 int 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 */