5cda85b9b8949ac226bad8f6962d18912cbf39df
[platform/upstream/curl.git] / lib / gskit.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_GSKIT
26
27 #include <gskssl.h>
28 #include <qsoasync.h>
29
30 /* Some symbols are undefined/unsupported on OS400 versions < V7R1. */
31 #ifndef GSK_SSL_EXTN_SERVERNAME_REQUEST
32 #define GSK_SSL_EXTN_SERVERNAME_REQUEST                 230
33 #endif
34
35 #ifdef HAVE_LIMITS_H
36 #  include <limits.h>
37 #endif
38
39 #include <curl/curl.h>
40 #include "urldata.h"
41 #include "sendf.h"
42 #include "gskit.h"
43 #include "sslgen.h"
44 #include "connect.h" /* for the connect timeout */
45 #include "select.h"
46 #include "strequal.h"
47 #include "x509asn1.h"
48
49 #define _MPRINTF_REPLACE /* use our functions only */
50 #include <curl/mprintf.h>
51
52 #include "curl_memory.h"
53 /* The last #include file should be: */
54 #include "memdebug.h"
55
56
57 /* Supported ciphers. */
58 typedef struct {
59   const char *  name;           /* Cipher name. */
60   const char *  gsktoken;       /* Corresponding token for GSKit String. */
61   int           sslver;         /* SSL version. */
62 }  gskit_cipher;
63
64 static const gskit_cipher  ciphertable[] = {
65   { "null-md5",         "01",   CURL_SSLVERSION_SSLv3 },
66   { "null-sha",         "02",   CURL_SSLVERSION_SSLv3 },
67   { "exp-rc4-md5",      "03",   CURL_SSLVERSION_SSLv3 },
68   { "rc4-md5",          "04",   CURL_SSLVERSION_SSLv3 },
69   { "rc4-sha",          "05",   CURL_SSLVERSION_SSLv3 },
70   { "exp-rc2-cbc-md5",  "06",   CURL_SSLVERSION_SSLv3 },
71   { "exp-des-cbc-sha",  "09",   CURL_SSLVERSION_SSLv3 },
72   { "des-cbc3-sha",     "0A",   CURL_SSLVERSION_SSLv3 },
73   { "aes128-sha",       "2F",   CURL_SSLVERSION_TLSv1 },
74   { "aes256-sha",       "35",   CURL_SSLVERSION_TLSv1 },
75   { "rc4-md5",          "1",    CURL_SSLVERSION_SSLv2 },
76   { "exp-rc4-md5",      "2",    CURL_SSLVERSION_SSLv2 },
77   { "rc2-md5",          "3",    CURL_SSLVERSION_SSLv2 },
78   { "exp-rc2-md5",      "4",    CURL_SSLVERSION_SSLv2 },
79   { "des-cbc-md5",      "6",    CURL_SSLVERSION_SSLv2 },
80   { "des-cbc3-md5",     "7",    CURL_SSLVERSION_SSLv2 },
81   { (const char *) NULL, (const char *) NULL, 0       }
82 };
83
84
85 static bool is_separator(char c)
86 {
87   /* Return whether character is a cipher list separator. */
88   switch (c) {
89   case ' ':
90   case '\t':
91   case ':':
92   case ',':
93   case ';':
94     return true;
95   }
96   return false;
97 }
98
99
100 static CURLcode gskit_status(struct SessionHandle * data, int rc,
101                              const char * procname, CURLcode defcode)
102 {
103   CURLcode cc;
104
105   /* Process GSKit status and map it to a CURLcode. */
106   switch (rc) {
107   case GSK_OK:
108   case GSK_OS400_ASYNCHRONOUS_SOC_INIT:
109     return CURLE_OK;
110   case GSK_KEYRING_OPEN_ERROR:
111   case GSK_OS400_ERROR_NO_ACCESS:
112     return CURLE_SSL_CACERT_BADFILE;
113   case GSK_INSUFFICIENT_STORAGE:
114     return CURLE_OUT_OF_MEMORY;
115   case GSK_ERROR_BAD_V2_CIPHER:
116   case GSK_ERROR_BAD_V3_CIPHER:
117   case GSK_ERROR_NO_CIPHERS:
118     return CURLE_SSL_CIPHER;
119   case GSK_OS400_ERROR_NOT_TRUSTED_ROOT:
120   case GSK_ERROR_CERT_VALIDATION:
121     return CURLE_PEER_FAILED_VERIFICATION;
122   case GSK_OS400_ERROR_TIMED_OUT:
123     return CURLE_OPERATION_TIMEDOUT;
124   case GSK_WOULD_BLOCK:
125     return CURLE_AGAIN;
126   case GSK_OS400_ERROR_NOT_REGISTERED:
127     break;
128   case GSK_ERROR_IO:
129     switch (errno) {
130     case ENOMEM:
131       return CURLE_OUT_OF_MEMORY;
132     default:
133       failf(data, "%s I/O error: %s", procname, strerror(errno));
134       break;
135     }
136     break;
137   default:
138     failf(data, "%s: %s", procname, gsk_strerror(rc));
139     break;
140     }
141   return defcode;
142 }
143
144
145 static CURLcode set_enum(struct SessionHandle * data,
146                          gsk_handle h, GSK_ENUM_ID id, GSK_ENUM_VALUE value)
147 {
148   int rc = gsk_attribute_set_enum(h, id, value);
149
150   switch (rc) {
151   case GSK_OK:
152     return CURLE_OK;
153   case GSK_ERROR_IO:
154     failf(data, "gsk_attribute_set_enum() I/O error: %s", strerror(errno));
155     break;
156   default:
157     failf(data, "gsk_attribute_set_enum(): %s", gsk_strerror(rc));
158     break;
159   }
160   return CURLE_SSL_CONNECT_ERROR;
161 }
162
163
164 static CURLcode set_buffer(struct SessionHandle * data,
165                            gsk_handle h, GSK_BUF_ID id, const char * buffer)
166 {
167   int rc = gsk_attribute_set_buffer(h, id, buffer, 0);
168
169   switch (rc) {
170   case GSK_OK:
171     return CURLE_OK;
172   case GSK_ERROR_IO:
173     failf(data, "gsk_attribute_set_buffer() I/O error: %s", strerror(errno));
174     break;
175   default:
176     failf(data, "gsk_attribute_set_buffer(): %s", gsk_strerror(rc));
177     break;
178   }
179   return CURLE_SSL_CONNECT_ERROR;
180 }
181
182
183 static CURLcode set_numeric(struct SessionHandle * data,
184                             gsk_handle h, GSK_NUM_ID id, int value)
185 {
186   int rc = gsk_attribute_set_numeric_value(h, id, value);
187
188   switch (rc) {
189   case GSK_OK:
190     return CURLE_OK;
191   case GSK_ERROR_IO:
192     failf(data, "gsk_attribute_set_numeric_value() I/O error: %s",
193           strerror(errno));
194     break;
195   default:
196     failf(data, "gsk_attribute_set_numeric_value(): %s", gsk_strerror(rc));
197     break;
198   }
199   return CURLE_SSL_CONNECT_ERROR;
200 }
201
202
203 static CURLcode set_callback(struct SessionHandle * data,
204                              gsk_handle h, GSK_CALLBACK_ID id, void * info)
205 {
206   int rc = gsk_attribute_set_callback(h, id, info);
207
208   switch (rc) {
209   case GSK_OK:
210     return CURLE_OK;
211   case GSK_ERROR_IO:
212     failf(data, "gsk_attribute_set_callback() I/O error: %s", strerror(errno));
213     break;
214   default:
215     failf(data, "gsk_attribute_set_callback(): %s", gsk_strerror(rc));
216     break;
217   }
218   return CURLE_SSL_CONNECT_ERROR;
219 }
220
221
222 static CURLcode set_ciphers(struct SessionHandle * data, gsk_handle h)
223 {
224   const char * cipherlist = data->set.str[STRING_SSL_CIPHER_LIST];
225   char * sslv2ciphers;
226   char * sslv3ciphers;
227   const char * clp;
228   const gskit_cipher * ctp;
229   char * v2p;
230   char * v3p;
231   int i;
232   CURLcode cc;
233
234   /* Compile cipher list into GSKit-compatible cipher lists. */
235
236   if(!cipherlist)
237     return CURLE_OK;
238   while(is_separator(*cipherlist))     /* Skip initial separators. */
239     cipherlist++;
240   if(!*cipherlist)
241     return CURLE_OK;
242
243   /* We allocate GSKit buffers of the same size as the input string: since
244      GSKit tokens are always shorter than their cipher names, allocated buffers
245      will always be large enough to accomodate the result. */
246   i = strlen(cipherlist) + 1;
247   v2p = malloc(i);
248   if(!v2p)
249     return CURLE_OUT_OF_MEMORY;
250   v3p = malloc(i);
251   if(!v3p) {
252     free(v2p);
253     return CURLE_OUT_OF_MEMORY;
254   }
255   sslv2ciphers = v2p;
256   sslv3ciphers = v3p;
257
258   /* Process each cipher in input string. */
259   for(;;) {
260     for(clp = cipherlist; *cipherlist && !is_separator(*cipherlist);)
261       cipherlist++;
262     i = cipherlist - clp;
263     if(!i)
264       break;
265     /* Search the cipher in our table. */
266     for(ctp = ciphertable; ctp->name; ctp++)
267       if(strnequal(ctp->name, clp, i) && !ctp->name[i])
268         break;
269     if(!ctp->name)
270       failf(data, "Unknown cipher %.*s: ignored", i, clp);
271     else {
272       switch (ctp->sslver) {
273       case CURL_SSLVERSION_SSLv2:
274         strcpy(v2p, ctp->gsktoken);
275         v2p += strlen(v2p);
276         break;
277       default:
278         /* GSKit wants TLSv1 ciphers with SSLv3 ciphers. */
279         strcpy(v3p, ctp->gsktoken);
280         v3p += strlen(v3p);
281         break;
282       }
283     }
284
285    /* Advance to next cipher name or end of string. */
286     while(is_separator(*cipherlist))
287       cipherlist++;
288   }
289   *v2p = '\0';
290   *v3p = '\0';
291   cc = set_buffer(data, h, GSK_V2_CIPHER_SPECS, sslv2ciphers);
292   if(cc == CURLE_OK)
293     cc = set_buffer(data, h, GSK_V3_CIPHER_SPECS, sslv3ciphers);
294   free(sslv2ciphers);
295   free(sslv3ciphers);
296   return cc;
297 }
298
299
300 int Curl_gskit_init(void)
301 {
302   /* No initialisation needed. */
303
304   return 1;
305 }
306
307
308 void Curl_gskit_cleanup(void)
309 {
310   /* Nothing to do. */
311 }
312
313
314 static CURLcode init_environment(struct SessionHandle * data,
315                                  gsk_handle * envir, const char * appid,
316                                  const char * file, const char * label,
317                                  const char * password)
318 {
319   int rc;
320   CURLcode c;
321   gsk_handle h;
322
323   /* Creates the GSKit environment. */
324
325   rc = gsk_environment_open(&h);
326   switch (rc) {
327   case GSK_OK:
328     break;
329   case GSK_INSUFFICIENT_STORAGE:
330     return CURLE_OUT_OF_MEMORY;
331   default:
332     failf(data, "gsk_environment_open(): %s", gsk_strerror(rc));
333     return CURLE_SSL_CONNECT_ERROR;
334   }
335
336   c = set_enum(data, h, GSK_SESSION_TYPE, GSK_CLIENT_SESSION);
337   if(c == CURLE_OK && appid)
338     c = set_buffer(data, h, GSK_OS400_APPLICATION_ID, appid);
339   if(c == CURLE_OK && file)
340     c = set_buffer(data, h, GSK_KEYRING_FILE, file);
341   if(c == CURLE_OK && label)
342     c = set_buffer(data, h, GSK_KEYRING_LABEL, label);
343   if(c == CURLE_OK && password)
344     c = set_buffer(data, h, GSK_KEYRING_PW, password);
345
346   if(c == CURLE_OK) {
347     /* Locate CAs, Client certificate and key according to our settings.
348        Note: this call may be blocking for some tenths of seconds. */
349     c = gskit_status(data, gsk_environment_init(h),
350                      "gsk_environment_init()", CURLE_SSL_CERTPROBLEM);
351     if(c == CURLE_OK) {
352       *envir = h;
353       return c;
354     }
355   }
356   /* Error: rollback. */
357   gsk_environment_close(&h);
358   return c;
359 }
360
361
362 static void cancel_async_handshake(struct connectdata * conn, int sockindex)
363 {
364   struct ssl_connect_data * connssl = &conn->ssl[sockindex];
365   Qso_OverlappedIO_t cstat;
366
367   if(QsoCancelOperation(conn->sock[sockindex], 0) > 0)
368     QsoWaitForIOCompletion(connssl->iocport, &cstat, (struct timeval *) NULL);
369 }
370
371
372 static void close_async_handshake(struct ssl_connect_data * connssl)
373 {
374   QsoDestroyIOCompletionPort(connssl->iocport);
375   connssl->iocport = -1;
376 }
377
378
379 static void close_one(struct ssl_connect_data * conn,
380                       struct SessionHandle * data)
381 {
382   if(conn->handle) {
383     gskit_status(data, gsk_secure_soc_close(&conn->handle),
384               "gsk_secure_soc_close()", 0);
385     conn->handle = (gsk_handle) NULL;
386   }
387   if(conn->iocport >= 0)
388     close_async_handshake(conn);
389 }
390
391
392 static ssize_t gskit_send(struct connectdata * conn, int sockindex,
393                            const void * mem, size_t len, CURLcode * curlcode)
394 {
395   struct SessionHandle * data = conn->data;
396   CURLcode cc;
397   int written;
398
399   cc = gskit_status(data,
400                     gsk_secure_soc_write(conn->ssl[sockindex].handle,
401                                          (char *) mem, (int) len, &written),
402                     "gsk_secure_soc_write()", CURLE_SEND_ERROR);
403   if(cc != CURLE_OK) {
404     *curlcode = cc;
405     written = -1;
406   }
407   return (ssize_t) written; /* number of bytes */
408 }
409
410
411 static ssize_t gskit_recv(struct connectdata * conn, int num, char * buf,
412                            size_t buffersize, CURLcode * curlcode)
413 {
414   struct SessionHandle * data = conn->data;
415   int buffsize;
416   int nread;
417   CURLcode cc;
418
419   buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize;
420   cc = gskit_status(data, gsk_secure_soc_read(conn->ssl[num].handle,
421                                               buf, buffsize, &nread),
422                     "gsk_secure_soc_read()", CURLE_RECV_ERROR);
423   if(cc != CURLE_OK) {
424     *curlcode = cc;
425     nread = -1;
426   }
427   return (ssize_t) nread;
428 }
429
430
431 static CURLcode gskit_connect_step1(struct connectdata * conn, int sockindex)
432 {
433   struct SessionHandle * data = conn->data;
434   struct ssl_connect_data * connssl = &conn->ssl[sockindex];
435   gsk_handle envir;
436   CURLcode cc;
437   int rc;
438   char * keyringfile;
439   char * keyringpwd;
440   char * keyringlabel;
441   char * v2ciphers;
442   char * v3ciphers;
443   char * sni;
444   bool sslv2enable, sslv3enable, tlsv1enable;
445   long timeout;
446   Qso_OverlappedIO_t commarea;
447
448   /* Create SSL environment, start (preferably asynchronous) handshake. */
449
450   connssl->handle = (gsk_handle) NULL;
451   connssl->iocport = -1;
452
453   /* GSKit supports two ways of specifying an SSL context: either by
454    *  application identifier (that should have been defined at the system
455    *  level) or by keyring file, password and certificate label.
456    * Local certificate name (CURLOPT_SSLCERT) is used to hold either the
457    *  application identifier of the certificate label.
458    * Key password (CURLOPT_KEYPASSWD) holds the keyring password.
459    * It is not possible to have different keyrings for the CAs and the
460    *  local certificate. We thus use the CA file (CURLOPT_CAINFO) to identify
461    *  the keyring file.
462    * If no key password is given and the keyring is the system keyring,
463    *  application identifier mode is tried first, as recommended in IBM doc.
464    */
465
466   keyringfile = data->set.str[STRING_SSL_CAFILE];
467   keyringpwd = data->set.str[STRING_KEY_PASSWD];
468   keyringlabel = data->set.str[STRING_CERT];
469   envir = (gsk_handle) NULL;
470
471   if(keyringlabel && *keyringlabel && !keyringpwd &&
472       !strcmp(keyringfile, CURL_CA_BUNDLE)) {
473     /* Try application identifier mode. */
474     init_environment(data, &envir, keyringlabel, (const char *) NULL,
475                      (const char *) NULL, (const char *) NULL);
476   }
477
478   if(!envir) {
479     /* Use keyring mode. */
480     cc = init_environment(data, &envir, (const char *) NULL,
481                           keyringfile, keyringlabel, keyringpwd);
482     if(cc != CURLE_OK)
483       return cc;
484   }
485
486   /* Create secure session. */
487   cc = gskit_status(data, gsk_secure_soc_open(envir, &connssl->handle),
488                     "gsk_secure_soc_open()", CURLE_SSL_CONNECT_ERROR);
489   gsk_environment_close(&envir);
490   if(cc != CURLE_OK)
491     return cc;
492
493   /* Determine which SSL/TLS version should be enabled. */
494   sslv2enable = sslv3enable = tlsv1enable = false;
495   sni = conn->host.name;
496   switch (data->set.ssl.version) {
497   case CURL_SSLVERSION_SSLv2:
498     sslv2enable = true;
499     sni = (char *) NULL;
500     break;
501   case CURL_SSLVERSION_SSLv3:
502     sslv3enable = true;
503     sni = (char *) NULL;
504     break;
505   case CURL_SSLVERSION_TLSv1:
506     tlsv1enable = true;
507     break;
508   default:              /* CURL_SSLVERSION_DEFAULT. */
509     sslv3enable = true;
510     tlsv1enable = true;
511     break;
512   }
513
514   /* Process SNI. Ignore if not supported (on OS400 < V7R1). */
515   if(sni) {
516     rc = gsk_attribute_set_buffer(connssl->handle,
517                                   GSK_SSL_EXTN_SERVERNAME_REQUEST, sni, 0);
518     switch (rc) {
519     case GSK_OK:
520     case GSK_ATTRIBUTE_INVALID_ID:
521       break;
522     case GSK_ERROR_IO:
523       failf(data, "gsk_attribute_set_buffer() I/O error: %s", strerror(errno));
524       cc = CURLE_SSL_CONNECT_ERROR;
525       break;
526     default:
527       failf(data, "gsk_attribute_set_buffer(): %s", gsk_strerror(rc));
528       cc = CURLE_SSL_CONNECT_ERROR;
529       break;
530     }
531   }
532
533   /* Set session parameters. */
534   if(cc == CURLE_OK) {
535     /* Compute the handshake timeout. Since GSKit granularity is 1 second,
536        we round up the required value. */
537     timeout = Curl_timeleft(data, NULL, TRUE);
538     if(timeout < 0)
539       cc = CURLE_OPERATION_TIMEDOUT;
540     else
541       cc = set_numeric(data, connssl->handle, GSK_HANDSHAKE_TIMEOUT,
542                        (timeout + 999) / 1000);
543   }
544   if(cc == CURLE_OK)
545     cc = set_numeric(data, connssl->handle, GSK_FD, conn->sock[sockindex]);
546   if(cc == CURLE_OK)
547     cc = set_ciphers(data, connssl->handle);
548   if(cc == CURLE_OK)
549       cc = set_enum(data, connssl->handle, GSK_PROTOCOL_SSLV2,
550                     sslv2enable? GSK_PROTOCOL_SSLV2_ON:
551                     GSK_PROTOCOL_SSLV2_OFF);
552   if(cc == CURLE_OK)
553     cc = set_enum(data, connssl->handle, GSK_PROTOCOL_SSLV3,
554                   sslv3enable? GSK_PROTOCOL_SSLV3_ON:
555                   GSK_PROTOCOL_SSLV3_OFF);
556   if(cc == CURLE_OK)
557     cc = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV1,
558                   sslv3enable?  GSK_PROTOCOL_TLSV1_ON:
559                   GSK_PROTOCOL_TLSV1_OFF);
560   if(cc == CURLE_OK)
561     cc = set_enum(data, connssl->handle, GSK_SERVER_AUTH_TYPE,
562                   data->set.ssl.verifypeer? GSK_SERVER_AUTH_FULL:
563                   GSK_SERVER_AUTH_PASSTHRU);
564
565   if(cc == CURLE_OK) {
566     /* Start handshake. Try asynchronous first. */
567     memset(&commarea, 0, sizeof commarea);
568     connssl->iocport = QsoCreateIOCompletionPort();
569     if(connssl->iocport != -1) {
570       cc = gskit_status(data, gsk_secure_soc_startInit(connssl->handle,
571                         connssl->iocport, &commarea),
572                         "gsk_secure_soc_startInit()", CURLE_SSL_CONNECT_ERROR);
573       if(cc == CURLE_OK) {
574         connssl->connecting_state = ssl_connect_2;
575         return CURLE_OK;
576       }
577       else
578         close_async_handshake(connssl);
579     }
580     else if(errno != ENOBUFS)
581       cc = gskit_status(data, GSK_ERROR_IO, "QsoCreateIOCompletionPort()", 0);
582     else {
583       /* No more completion port available. Use synchronous IO. */
584       cc = gskit_status(data, gsk_secure_soc_init(connssl->handle),
585                        "gsk_secure_soc_init()", CURLE_SSL_CONNECT_ERROR);
586       if(cc == CURLE_OK) {
587         connssl->connecting_state = ssl_connect_3;
588         return CURLE_OK;
589       }
590     }
591   }
592
593   /* Error: rollback. */
594   close_one(connssl, data);
595   return cc;
596 }
597
598
599 static CURLcode gskit_connect_step2(struct connectdata * conn, int sockindex,
600                                     bool nonblocking)
601 {
602   struct SessionHandle * data = conn->data;
603   struct ssl_connect_data * connssl = &conn->ssl[sockindex];
604   Qso_OverlappedIO_t cstat;
605   long timeout_ms;
606   struct timeval stmv;
607   CURLcode cc;
608
609   /* Poll or wait for end of SSL asynchronous handshake. */
610
611   for(;;) {
612     timeout_ms = nonblocking? 0: Curl_timeleft(data, NULL, TRUE);
613     if(timeout_ms < 0)
614       timeout_ms = 0;
615     stmv.tv_sec = timeout_ms / 1000;
616     stmv.tv_usec = (timeout_ms - stmv.tv_sec * 1000) * 1000;
617     switch (QsoWaitForIOCompletion(connssl->iocport, &cstat, &stmv)) {
618     case 1:             /* Operation complete. */
619       break;
620     case -1:            /* An error occurred: handshake still in progress. */
621       if(errno == EINTR) {
622         if(nonblocking)
623           return CURLE_OK;
624         continue;       /* Retry. */
625       }
626       if(errno != ETIME) {
627         failf(data, "QsoWaitForIOCompletion() I/O error: %s", strerror(errno));
628         cancel_async_handshake(conn, sockindex);
629         close_async_handshake(connssl);
630         return CURLE_SSL_CONNECT_ERROR;
631       }
632       /* FALL INTO... */
633     case 0:             /* Handshake in progress, timeout occurred. */
634       if(nonblocking)
635         return CURLE_OK;
636       cancel_async_handshake(conn, sockindex);
637       close_async_handshake(connssl);
638       return CURLE_OPERATION_TIMEDOUT;
639     }
640     break;
641   }
642   cc = gskit_status(data, cstat.returnValue, "SSL handshake",
643                     CURLE_SSL_CONNECT_ERROR);
644   if(cc == CURLE_OK)
645     connssl->connecting_state = ssl_connect_3;
646   close_async_handshake(connssl);
647   return cc;
648 }
649
650
651 static CURLcode gskit_connect_step3(struct connectdata * conn, int sockindex)
652 {
653   struct SessionHandle * data = conn->data;
654   struct ssl_connect_data * connssl = &conn->ssl[sockindex];
655   const gsk_cert_data_elem * cdev;
656   int cdec;
657   const gsk_cert_data_elem * p;
658   const char * cert = (const char *) NULL;
659   const char * certend;
660   int i;
661   CURLcode cc;
662
663   /* SSL handshake done: gather certificate info and verify host. */
664
665   if(gskit_status(data, gsk_attribute_get_cert_info(connssl->handle,
666                                                     GSK_PARTNER_CERT_INFO,
667                                                     &cdev, &cdec),
668                   "gsk_attribute_get_cert_info()", CURLE_SSL_CONNECT_ERROR) ==
669      CURLE_OK) {
670     infof(data, "Server certificate:\n");
671     p = cdev;
672     for(i = 0; i++ < cdec; p++)
673       switch (p->cert_data_id) {
674       case CERT_BODY_DER:
675         cert = p->cert_data_p;
676         certend = cert + cdev->cert_data_l;
677         break;
678       case CERT_DN_PRINTABLE:
679         infof(data, "\t subject: %.*s\n", p->cert_data_l, p->cert_data_p);
680         break;
681       case CERT_ISSUER_DN_PRINTABLE:
682         infof(data, "\t issuer: %.*s\n", p->cert_data_l, p->cert_data_p);
683         break;
684       case CERT_VALID_FROM:
685         infof(data, "\t start date: %.*s\n", p->cert_data_l, p->cert_data_p);
686         break;
687       case CERT_VALID_TO:
688         infof(data, "\t expire date: %.*s\n", p->cert_data_l, p->cert_data_p);
689         break;
690     }
691   }
692
693   /* Verify host. */
694   cc = Curl_verifyhost(conn, cert, certend);
695   if(cc != CURLE_OK)
696     return cc;
697
698   /* The only place GSKit can get the whole CA chain is a validation
699      callback where no user data pointer is available. Therefore it's not
700      possible to copy this chain into our structures for CAINFO.
701      However the server certificate may be available, thus we can return
702      info about it. */
703   if(data->set.ssl.certinfo) {
704     if(Curl_ssl_init_certinfo(data, 1))
705       return CURLE_OUT_OF_MEMORY;
706     if(cert) {
707       cc = Curl_extract_certinfo(conn, 0, cert, certend);
708       if(cc != CURLE_OK)
709         return cc;
710     }
711   }
712
713   connssl->connecting_state = ssl_connect_done;
714   return CURLE_OK;
715 }
716
717
718 static CURLcode gskit_connect_common(struct connectdata * conn, int sockindex,
719                                      bool nonblocking, bool * done)
720 {
721   struct SessionHandle * data = conn->data;
722   struct ssl_connect_data * connssl = &conn->ssl[sockindex];
723   long timeout_ms;
724   Qso_OverlappedIO_t cstat;
725   CURLcode cc = CURLE_OK;
726
727   *done = connssl->state == ssl_connection_complete;
728   if(*done)
729     return CURLE_OK;
730
731   /* Step 1: create session, start handshake. */
732   if(connssl->connecting_state == ssl_connect_1) {
733     /* check allowed time left */
734     timeout_ms = Curl_timeleft(data, NULL, TRUE);
735
736     if(timeout_ms < 0) {
737       /* no need to continue if time already is up */
738       failf(data, "SSL connection timeout");
739       cc = CURLE_OPERATION_TIMEDOUT;
740     }
741     else
742       cc = gskit_connect_step1(conn, sockindex);
743   }
744
745   /* Step 2: check if handshake is over. */
746   if(cc == CURLE_OK && connssl->connecting_state == ssl_connect_2) {
747     /* check allowed time left */
748     timeout_ms = Curl_timeleft(data, NULL, TRUE);
749
750     if(timeout_ms < 0) {
751       /* no need to continue if time already is up */
752       failf(data, "SSL connection timeout");
753       cc = CURLE_OPERATION_TIMEDOUT;
754     }
755     else
756       cc = gskit_connect_step2(conn, sockindex, nonblocking);
757   }
758
759   /* Step 3: gather certificate info, verify host. */
760   if(cc == CURLE_OK && connssl->connecting_state == ssl_connect_3)
761     cc = gskit_connect_step3(conn, sockindex);
762
763   if(cc != CURLE_OK)
764     close_one(connssl, data);
765   else if(connssl->connecting_state == ssl_connect_done) {
766     connssl->state = ssl_connection_complete;
767     connssl->connecting_state = ssl_connect_1;
768     conn->recv[sockindex] = gskit_recv;
769     conn->send[sockindex] = gskit_send;
770     *done = TRUE;
771   }
772
773   return cc;
774 }
775
776
777 CURLcode Curl_gskit_connect_nonblocking(struct connectdata * conn,
778                                         int sockindex,
779                                         bool * done)
780 {
781   CURLcode cc;
782
783   cc = gskit_connect_common(conn, sockindex, TRUE, done);
784   if(*done || cc != CURLE_OK)
785     conn->ssl[sockindex].connecting_state = ssl_connect_1;
786   return cc;
787 }
788
789
790 CURLcode Curl_gskit_connect(struct connectdata * conn, int sockindex)
791 {
792   CURLcode retcode;
793   bool done;
794
795   conn->ssl[sockindex].connecting_state = ssl_connect_1;
796   retcode = gskit_connect_common(conn, sockindex, FALSE, &done);
797   if(retcode)
798     return retcode;
799
800   DEBUGASSERT(done);
801
802   return CURLE_OK;
803 }
804
805
806 void Curl_gskit_close(struct connectdata * conn, int sockindex)
807 {
808   struct SessionHandle * data = conn->data;
809   struct ssl_connect_data * connssl = &conn->ssl[sockindex];
810
811   if(connssl->use)
812     close_one(connssl, data);
813 }
814
815
816 int Curl_gskit_close_all(struct SessionHandle * data)
817 {
818   /* Unimplemented. */
819   (void) data;
820   return 0;
821 }
822
823
824 int Curl_gskit_shutdown(struct connectdata * conn, int sockindex)
825 {
826   struct ssl_connect_data * connssl = &conn->ssl[sockindex];
827   struct SessionHandle * data = conn->data;
828   ssize_t nread;
829   int what;
830   int rc;
831   char buf[120];
832
833   if(!connssl->handle)
834     return 0;
835
836   if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
837     return 0;
838
839   close_one(connssl, data);
840   rc = 0;
841   what = Curl_socket_ready(conn->sock[sockindex],
842                            CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
843
844   for(;;) {
845     if(what < 0) {
846       /* anything that gets here is fatally bad */
847       failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
848       rc = -1;
849       break;
850     }
851
852     if(!what) {                                /* timeout */
853       failf(data, "SSL shutdown timeout");
854       break;
855     }
856
857     /* Something to read, let's do it and hope that it is the close
858        notify alert from the server. No way to gsk_secure_soc_read() now, so
859        use read(). */
860
861     nread = read(conn->sock[sockindex], buf, sizeof(buf));
862
863     if(nread < 0) {
864       failf(data, "read: %s", strerror(errno));
865       rc = -1;
866     }
867
868     if(nread <= 0)
869       break;
870
871     what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0);
872   }
873
874   return rc;
875 }
876
877
878 size_t Curl_gskit_version(char * buffer, size_t size)
879 {
880   strncpy(buffer, "GSKit", size);
881   return strlen(buffer);
882 }
883
884
885 int Curl_gskit_check_cxn(struct connectdata * cxn)
886 {
887   int err;
888   int errlen;
889
890   /* The only thing that can be tested here is at the socket level. */
891
892   if(!cxn->ssl[FIRSTSOCKET].handle)
893     return 0; /* connection has been closed */
894
895   err = 0;
896   errlen = sizeof err;
897
898   if(getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR,
899                  (unsigned char *) &err, &errlen) ||
900      errlen != sizeof err || err)
901     return 0; /* connection has been closed */
902
903   return -1;  /* connection status unknown */
904 }
905
906 #endif /* USE_GSKIT */