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