source: UsbWattMeter/trunk/curl-7.47.1/lib/vtls/gskit.c@ 164

Last change on this file since 164 was 164, checked in by coas-nagasima, 8 years ago

TOPPERS/ECNLサンプルアプリ「USB充電器電力計」を追加

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-csrc
File size: 31.8 KB
RevLine 
[164]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 https://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. */
99typedef 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
105static 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
151static 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
166static 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
209static 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
231static 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
253static 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
273static 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
292static 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
425int Curl_gskit_init(void)
426{
427 /* No initialisation needed. */
428
429 return 1;
430}
431
432
433void Curl_gskit_cleanup(void)
434{
435 /* Nothing to do. */
436}
437
438
439static 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
487static 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
497static void close_async_handshake(struct ssl_connect_data *connssl)
498{
499 QsoDestroyIOCompletionPort(connssl->iocport);
500 connssl->iocport = -1;
501}
502
503
504static 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
517static 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
536static 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
556static 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
750static 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
802static 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(data, 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
889static 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
948CURLcode 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
961CURLcode 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
977void 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
987int 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
1041size_t Curl_gskit_version(char *buffer, size_t size)
1042{
1043 strncpy(buffer, "GSKit", size);
1044 return strlen(buffer);
1045}
1046
1047
1048int 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 */
Note: See TracBrowser for help on using the repository browser.