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