Revert "Update to 7.40.1"
[platform/upstream/curl.git] / lib / vtls / 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 "vtls.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   case CURL_SSLVERSION_TLSv1_0:
209   case CURL_SSLVERSION_TLSv1_1:
210   case CURL_SSLVERSION_TLSv1_2:
211     failf(data, "TLS minor version cannot be set");
212     return CURLE_SSL_CONNECT_ERROR;
213   }
214
215   h->peerCert = NULL;
216   h->peerCertLen = 0;
217   rc = SSL_Handshake(h, SSL_HANDSHAKE_AS_CLIENT);
218
219   switch (rc) {
220
221   case 0:                             /* No error. */
222     break;
223
224   case SSL_ERROR_BAD_CERTIFICATE:
225   case SSL_ERROR_BAD_CERT_SIG:
226   case SSL_ERROR_NOT_TRUSTED_ROOT:
227     return CURLE_PEER_FAILED_VERIFICATION;
228
229   case SSL_ERROR_BAD_CIPHER_SUITE:
230   case SSL_ERROR_NO_CIPHERS:
231     return CURLE_SSL_CIPHER;
232
233   case SSL_ERROR_CERTIFICATE_REJECTED:
234   case SSL_ERROR_CERT_EXPIRED:
235   case SSL_ERROR_NO_CERTIFICATE:
236     return CURLE_SSL_CERTPROBLEM;
237
238   case SSL_ERROR_IO:
239     failf(data, "SSL_Handshake() I/O error: %s", strerror(errno));
240     return CURLE_SSL_CONNECT_ERROR;
241
242   default:
243     failf(data, "SSL_Handshake(): %s", SSL_Strerror(rc, NULL));
244     return CURLE_SSL_CONNECT_ERROR;
245   }
246
247   /* Verify host. */
248   rc = Curl_verifyhost(conn, h->peerCert, h->peerCert + h->peerCertLen);
249   if(rc != CURLE_OK)
250     return rc;
251
252   /* Gather certificate info. */
253   if(data->set.ssl.certinfo) {
254     if(Curl_ssl_init_certinfo(data, 1))
255       return CURLE_OUT_OF_MEMORY;
256     if(h->peerCert) {
257       rc = Curl_extract_certinfo(conn, 0, h->peerCert,
258                                  h->peerCert + h->peerCertLen);
259       if(rc != CURLE_OK)
260         return rc;
261     }
262   }
263
264   return CURLE_OK;
265 }
266
267
268 static Curl_recv qsossl_recv;
269 static Curl_send qsossl_send;
270
271 CURLcode Curl_qsossl_connect(struct connectdata * conn, int sockindex)
272
273 {
274   struct SessionHandle * data = conn->data;
275   struct ssl_connect_data * connssl = &conn->ssl[sockindex];
276   int rc;
277
278   rc = Curl_qsossl_init_session(data);
279
280   if(rc == CURLE_OK) {
281     rc = Curl_qsossl_create(conn, sockindex);
282
283     if(rc == CURLE_OK) {
284       rc = Curl_qsossl_handshake(conn, sockindex);
285       if(rc != CURLE_OK)
286         SSL_Destroy(connssl->handle);
287     }
288   }
289
290   if(rc == CURLE_OK) {
291     conn->recv[sockindex] = qsossl_recv;
292     conn->send[sockindex] = qsossl_send;
293     connssl->state = ssl_connection_complete;
294   }
295   else {
296     connssl->handle = NULL;
297     connssl->use = FALSE;
298     connssl->state = ssl_connection_none;
299   }
300
301   return rc;
302 }
303
304
305 static int Curl_qsossl_close_one(struct ssl_connect_data * conn,
306                                  struct SessionHandle * data)
307
308 {
309   int rc;
310
311   if(!conn->handle)
312     return 0;
313
314   rc = SSL_Destroy(conn->handle);
315
316   if(rc) {
317     if(rc == SSL_ERROR_IO) {
318       failf(data, "SSL_Destroy() I/O error: %s", strerror(errno));
319       return -1;
320     }
321
322     /* An SSL error. */
323     failf(data, "SSL_Destroy() returned error %s", SSL_Strerror(rc, NULL));
324     return -1;
325   }
326
327   conn->handle = NULL;
328   return 0;
329 }
330
331
332 void Curl_qsossl_close(struct connectdata *conn, int sockindex)
333
334 {
335   struct SessionHandle *data = conn->data;
336   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
337
338   if(connssl->use)
339     (void) Curl_qsossl_close_one(connssl, data);
340 }
341
342
343 int Curl_qsossl_close_all(struct SessionHandle * data)
344
345 {
346   /* Unimplemented. */
347   (void) data;
348   return 0;
349 }
350
351
352 int Curl_qsossl_shutdown(struct connectdata * conn, int sockindex)
353
354 {
355   struct ssl_connect_data * connssl = &conn->ssl[sockindex];
356   struct SessionHandle *data = conn->data;
357   ssize_t nread;
358   int what;
359   int rc;
360   char buf[120];
361
362   if(!connssl->handle)
363     return 0;
364
365   if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
366     return 0;
367
368   if(Curl_qsossl_close_one(connssl, data))
369     return -1;
370
371   rc = 0;
372
373   what = Curl_socket_ready(conn->sock[sockindex],
374                            CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
375
376   for(;;) {
377     if(what < 0) {
378       /* anything that gets here is fatally bad */
379       failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
380       rc = -1;
381       break;
382     }
383
384     if(!what) {                                /* timeout */
385       failf(data, "SSL shutdown timeout");
386       break;
387     }
388
389     /* Something to read, let's do it and hope that it is the close
390        notify alert from the server. No way to SSL_Read now, so use read(). */
391
392     nread = read(conn->sock[sockindex], buf, sizeof(buf));
393
394     if(nread < 0) {
395       failf(data, "read: %s", strerror(errno));
396       rc = -1;
397     }
398
399     if(nread <= 0)
400       break;
401
402     what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0);
403   }
404
405   return rc;
406 }
407
408
409 static ssize_t qsossl_send(struct connectdata * conn, int sockindex,
410                            const void * mem, size_t len, CURLcode * curlcode)
411
412 {
413   /* SSL_Write() is said to return 'int' while write() and send() returns
414      'size_t' */
415   int rc;
416
417   rc = SSL_Write(conn->ssl[sockindex].handle, (void *) mem, (int) len);
418
419   if(rc < 0) {
420     switch(rc) {
421
422     case SSL_ERROR_BAD_STATE:
423       /* The operation did not complete; the same SSL I/O function
424          should be called again later. This is basically an EWOULDBLOCK
425          equivalent. */
426       *curlcode = CURLE_AGAIN;
427       return -1;
428
429     case SSL_ERROR_IO:
430       switch (errno) {
431       case EWOULDBLOCK:
432       case EINTR:
433         *curlcode = CURLE_AGAIN;
434         return -1;
435         }
436
437       failf(conn->data, "SSL_Write() I/O error: %s", strerror(errno));
438       *curlcode = CURLE_SEND_ERROR;
439       return -1;
440     }
441
442     /* An SSL error. */
443     failf(conn->data, "SSL_Write() returned error %s",
444           SSL_Strerror(rc, NULL));
445     *curlcode = CURLE_SEND_ERROR;
446     return -1;
447   }
448
449   return (ssize_t) rc; /* number of bytes */
450 }
451
452
453 static ssize_t qsossl_recv(struct connectdata * conn, int num, char * buf,
454                            size_t buffersize, CURLcode * curlcode)
455
456 {
457   char error_buffer[120]; /* OpenSSL documents that this must be at
458                              least 120 bytes long. */
459   unsigned long sslerror;
460   int buffsize;
461   int nread;
462
463   buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
464   nread = SSL_Read(conn->ssl[num].handle, buf, buffsize);
465
466   if(nread < 0) {
467     /* failed SSL_read */
468
469     switch (nread) {
470
471     case SSL_ERROR_BAD_STATE:
472       /* there's data pending, re-invoke SSL_Read(). */
473       *curlcode = CURLE_AGAIN;
474       return -1;
475
476     case SSL_ERROR_IO:
477       switch (errno) {
478       case EWOULDBLOCK:
479         *curlcode = CURLE_AGAIN;
480         return -1;
481         }
482
483       failf(conn->data, "SSL_Read() I/O error: %s", strerror(errno));
484       *curlcode = CURLE_RECV_ERROR;
485       return -1;
486
487     default:
488       failf(conn->data, "SSL read error: %s", SSL_Strerror(nread, NULL));
489       *curlcode = CURLE_RECV_ERROR;
490       return -1;
491     }
492   }
493   return (ssize_t) nread;
494 }
495
496
497 size_t Curl_qsossl_version(char * buffer, size_t size)
498
499 {
500   strncpy(buffer, "IBM OS/400 SSL", size);
501   return strlen(buffer);
502 }
503
504
505 int Curl_qsossl_check_cxn(struct connectdata * cxn)
506
507 {
508   int err;
509   int errlen;
510
511   /* The only thing that can be tested here is at the socket level. */
512
513   if(!cxn->ssl[FIRSTSOCKET].handle)
514     return 0; /* connection has been closed */
515
516   err = 0;
517   errlen = sizeof err;
518
519   if(getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR,
520                  (unsigned char *) &err, &errlen) ||
521       errlen != sizeof err || err)
522     return 0; /* connection has been closed */
523
524   return -1;  /* connection status unknown */
525 }
526
527 #endif /* USE_QSOSSL */