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