1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
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.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
23 #include "curl_setup.h"
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
39 #include <curl/curl.h>
44 #include "connect.h" /* for the connect timeout */
49 #define _MPRINTF_REPLACE /* use our functions only */
50 #include <curl/mprintf.h>
52 #include "curl_memory.h"
53 /* The last #include file should be: */
57 /* Supported ciphers. */
59 const char * name; /* Cipher name. */
60 const char * gsktoken; /* Corresponding token for GSKit String. */
61 int sslver; /* SSL version. */
64 static const gskit_cipher ciphertable[] = {
65 { "null-md5", "01", CURL_SSLVERSION_SSLv3 },
66 { "null-sha", "02", CURL_SSLVERSION_SSLv3 },
67 { "exp-rc4-md5", "03", CURL_SSLVERSION_SSLv3 },
68 { "rc4-md5", "04", CURL_SSLVERSION_SSLv3 },
69 { "rc4-sha", "05", CURL_SSLVERSION_SSLv3 },
70 { "exp-rc2-cbc-md5", "06", CURL_SSLVERSION_SSLv3 },
71 { "exp-des-cbc-sha", "09", CURL_SSLVERSION_SSLv3 },
72 { "des-cbc3-sha", "0A", CURL_SSLVERSION_SSLv3 },
73 { "aes128-sha", "2F", CURL_SSLVERSION_TLSv1 },
74 { "aes256-sha", "35", CURL_SSLVERSION_TLSv1 },
75 { "rc4-md5", "1", CURL_SSLVERSION_SSLv2 },
76 { "exp-rc4-md5", "2", CURL_SSLVERSION_SSLv2 },
77 { "rc2-md5", "3", CURL_SSLVERSION_SSLv2 },
78 { "exp-rc2-md5", "4", CURL_SSLVERSION_SSLv2 },
79 { "des-cbc-md5", "6", CURL_SSLVERSION_SSLv2 },
80 { "des-cbc3-md5", "7", CURL_SSLVERSION_SSLv2 },
81 { (const char *) NULL, (const char *) NULL, 0 }
85 static bool is_separator(char c)
87 /* Return whether character is a cipher list separator. */
100 static CURLcode gskit_status(struct SessionHandle * data, int rc,
101 const char * procname, CURLcode defcode)
105 /* Process GSKit status and map it to a CURLcode. */
108 case GSK_OS400_ASYNCHRONOUS_SOC_INIT:
110 case GSK_KEYRING_OPEN_ERROR:
111 case GSK_OS400_ERROR_NO_ACCESS:
112 return CURLE_SSL_CACERT_BADFILE;
113 case GSK_INSUFFICIENT_STORAGE:
114 return CURLE_OUT_OF_MEMORY;
115 case GSK_ERROR_BAD_V2_CIPHER:
116 case GSK_ERROR_BAD_V3_CIPHER:
117 case GSK_ERROR_NO_CIPHERS:
118 return CURLE_SSL_CIPHER;
119 case GSK_OS400_ERROR_NOT_TRUSTED_ROOT:
120 case GSK_ERROR_CERT_VALIDATION:
121 return CURLE_PEER_FAILED_VERIFICATION;
122 case GSK_OS400_ERROR_TIMED_OUT:
123 return CURLE_OPERATION_TIMEDOUT;
124 case GSK_WOULD_BLOCK:
126 case GSK_OS400_ERROR_NOT_REGISTERED:
131 return CURLE_OUT_OF_MEMORY;
133 failf(data, "%s I/O error: %s", procname, strerror(errno));
138 failf(data, "%s: %s", procname, gsk_strerror(rc));
145 static CURLcode set_enum(struct SessionHandle * data,
146 gsk_handle h, GSK_ENUM_ID id, GSK_ENUM_VALUE value)
148 int rc = gsk_attribute_set_enum(h, id, value);
154 failf(data, "gsk_attribute_set_enum() I/O error: %s", strerror(errno));
157 failf(data, "gsk_attribute_set_enum(): %s", gsk_strerror(rc));
160 return CURLE_SSL_CONNECT_ERROR;
164 static CURLcode set_buffer(struct SessionHandle * data,
165 gsk_handle h, GSK_BUF_ID id, const char * buffer)
167 int rc = gsk_attribute_set_buffer(h, id, buffer, 0);
173 failf(data, "gsk_attribute_set_buffer() I/O error: %s", strerror(errno));
176 failf(data, "gsk_attribute_set_buffer(): %s", gsk_strerror(rc));
179 return CURLE_SSL_CONNECT_ERROR;
183 static CURLcode set_numeric(struct SessionHandle * data,
184 gsk_handle h, GSK_NUM_ID id, int value)
186 int rc = gsk_attribute_set_numeric_value(h, id, value);
192 failf(data, "gsk_attribute_set_numeric_value() I/O error: %s",
196 failf(data, "gsk_attribute_set_numeric_value(): %s", gsk_strerror(rc));
199 return CURLE_SSL_CONNECT_ERROR;
203 static CURLcode set_callback(struct SessionHandle * data,
204 gsk_handle h, GSK_CALLBACK_ID id, void * info)
206 int rc = gsk_attribute_set_callback(h, id, info);
212 failf(data, "gsk_attribute_set_callback() I/O error: %s", strerror(errno));
215 failf(data, "gsk_attribute_set_callback(): %s", gsk_strerror(rc));
218 return CURLE_SSL_CONNECT_ERROR;
222 static CURLcode set_ciphers(struct SessionHandle * data, gsk_handle h)
224 const char * cipherlist = data->set.str[STRING_SSL_CIPHER_LIST];
228 const gskit_cipher * ctp;
234 /* Compile cipher list into GSKit-compatible cipher lists. */
238 while(is_separator(*cipherlist)) /* Skip initial separators. */
243 /* We allocate GSKit buffers of the same size as the input string: since
244 GSKit tokens are always shorter than their cipher names, allocated buffers
245 will always be large enough to accomodate the result. */
246 i = strlen(cipherlist) + 1;
249 return CURLE_OUT_OF_MEMORY;
253 return CURLE_OUT_OF_MEMORY;
258 /* Process each cipher in input string. */
260 for(clp = cipherlist; *cipherlist && !is_separator(*cipherlist);)
262 i = cipherlist - clp;
265 /* Search the cipher in our table. */
266 for(ctp = ciphertable; ctp->name; ctp++)
267 if(strnequal(ctp->name, clp, i) && !ctp->name[i])
270 failf(data, "Unknown cipher %.*s: ignored", i, clp);
272 switch (ctp->sslver) {
273 case CURL_SSLVERSION_SSLv2:
274 strcpy(v2p, ctp->gsktoken);
278 /* GSKit wants TLSv1 ciphers with SSLv3 ciphers. */
279 strcpy(v3p, ctp->gsktoken);
285 /* Advance to next cipher name or end of string. */
286 while(is_separator(*cipherlist))
291 cc = set_buffer(data, h, GSK_V2_CIPHER_SPECS, sslv2ciphers);
293 cc = set_buffer(data, h, GSK_V3_CIPHER_SPECS, sslv3ciphers);
300 int Curl_gskit_init(void)
302 /* No initialisation needed. */
308 void Curl_gskit_cleanup(void)
314 static CURLcode init_environment(struct SessionHandle * data,
315 gsk_handle * envir, const char * appid,
316 const char * file, const char * label,
317 const char * password)
323 /* Creates the GSKit environment. */
325 rc = gsk_environment_open(&h);
329 case GSK_INSUFFICIENT_STORAGE:
330 return CURLE_OUT_OF_MEMORY;
332 failf(data, "gsk_environment_open(): %s", gsk_strerror(rc));
333 return CURLE_SSL_CONNECT_ERROR;
336 c = set_enum(data, h, GSK_SESSION_TYPE, GSK_CLIENT_SESSION);
337 if(c == CURLE_OK && appid)
338 c = set_buffer(data, h, GSK_OS400_APPLICATION_ID, appid);
339 if(c == CURLE_OK && file)
340 c = set_buffer(data, h, GSK_KEYRING_FILE, file);
341 if(c == CURLE_OK && label)
342 c = set_buffer(data, h, GSK_KEYRING_LABEL, label);
343 if(c == CURLE_OK && password)
344 c = set_buffer(data, h, GSK_KEYRING_PW, password);
347 /* Locate CAs, Client certificate and key according to our settings.
348 Note: this call may be blocking for some tenths of seconds. */
349 c = gskit_status(data, gsk_environment_init(h),
350 "gsk_environment_init()", CURLE_SSL_CERTPROBLEM);
356 /* Error: rollback. */
357 gsk_environment_close(&h);
362 static void cancel_async_handshake(struct connectdata * conn, int sockindex)
364 struct ssl_connect_data * connssl = &conn->ssl[sockindex];
365 Qso_OverlappedIO_t cstat;
367 if(QsoCancelOperation(conn->sock[sockindex], 0) > 0)
368 QsoWaitForIOCompletion(connssl->iocport, &cstat, (struct timeval *) NULL);
372 static void close_async_handshake(struct ssl_connect_data * connssl)
374 QsoDestroyIOCompletionPort(connssl->iocport);
375 connssl->iocport = -1;
379 static void close_one(struct ssl_connect_data * conn,
380 struct SessionHandle * data)
383 gskit_status(data, gsk_secure_soc_close(&conn->handle),
384 "gsk_secure_soc_close()", 0);
385 conn->handle = (gsk_handle) NULL;
387 if(conn->iocport >= 0)
388 close_async_handshake(conn);
392 static ssize_t gskit_send(struct connectdata * conn, int sockindex,
393 const void * mem, size_t len, CURLcode * curlcode)
395 struct SessionHandle * data = conn->data;
399 cc = gskit_status(data,
400 gsk_secure_soc_write(conn->ssl[sockindex].handle,
401 (char *) mem, (int) len, &written),
402 "gsk_secure_soc_write()", CURLE_SEND_ERROR);
407 return (ssize_t) written; /* number of bytes */
411 static ssize_t gskit_recv(struct connectdata * conn, int num, char * buf,
412 size_t buffersize, CURLcode * curlcode)
414 struct SessionHandle * data = conn->data;
419 buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize;
420 cc = gskit_status(data, gsk_secure_soc_read(conn->ssl[num].handle,
421 buf, buffsize, &nread),
422 "gsk_secure_soc_read()", CURLE_RECV_ERROR);
427 return (ssize_t) nread;
431 static CURLcode gskit_connect_step1(struct connectdata * conn, int sockindex)
433 struct SessionHandle * data = conn->data;
434 struct ssl_connect_data * connssl = &conn->ssl[sockindex];
444 bool sslv2enable, sslv3enable, tlsv1enable;
446 Qso_OverlappedIO_t commarea;
448 /* Create SSL environment, start (preferably asynchronous) handshake. */
450 connssl->handle = (gsk_handle) NULL;
451 connssl->iocport = -1;
453 /* GSKit supports two ways of specifying an SSL context: either by
454 * application identifier (that should have been defined at the system
455 * level) or by keyring file, password and certificate label.
456 * Local certificate name (CURLOPT_SSLCERT) is used to hold either the
457 * application identifier of the certificate label.
458 * Key password (CURLOPT_KEYPASSWD) holds the keyring password.
459 * It is not possible to have different keyrings for the CAs and the
460 * local certificate. We thus use the CA file (CURLOPT_CAINFO) to identify
462 * If no key password is given and the keyring is the system keyring,
463 * application identifier mode is tried first, as recommended in IBM doc.
466 keyringfile = data->set.str[STRING_SSL_CAFILE];
467 keyringpwd = data->set.str[STRING_KEY_PASSWD];
468 keyringlabel = data->set.str[STRING_CERT];
469 envir = (gsk_handle) NULL;
471 if(keyringlabel && *keyringlabel && !keyringpwd &&
472 !strcmp(keyringfile, CURL_CA_BUNDLE)) {
473 /* Try application identifier mode. */
474 init_environment(data, &envir, keyringlabel, (const char *) NULL,
475 (const char *) NULL, (const char *) NULL);
479 /* Use keyring mode. */
480 cc = init_environment(data, &envir, (const char *) NULL,
481 keyringfile, keyringlabel, keyringpwd);
486 /* Create secure session. */
487 cc = gskit_status(data, gsk_secure_soc_open(envir, &connssl->handle),
488 "gsk_secure_soc_open()", CURLE_SSL_CONNECT_ERROR);
489 gsk_environment_close(&envir);
493 /* Determine which SSL/TLS version should be enabled. */
494 sslv2enable = sslv3enable = tlsv1enable = false;
495 sni = conn->host.name;
496 switch (data->set.ssl.version) {
497 case CURL_SSLVERSION_SSLv2:
501 case CURL_SSLVERSION_SSLv3:
505 case CURL_SSLVERSION_TLSv1:
508 default: /* CURL_SSLVERSION_DEFAULT. */
514 /* Process SNI. Ignore if not supported (on OS400 < V7R1). */
516 rc = gsk_attribute_set_buffer(connssl->handle,
517 GSK_SSL_EXTN_SERVERNAME_REQUEST, sni, 0);
520 case GSK_ATTRIBUTE_INVALID_ID:
523 failf(data, "gsk_attribute_set_buffer() I/O error: %s", strerror(errno));
524 cc = CURLE_SSL_CONNECT_ERROR;
527 failf(data, "gsk_attribute_set_buffer(): %s", gsk_strerror(rc));
528 cc = CURLE_SSL_CONNECT_ERROR;
533 /* Set session parameters. */
535 /* Compute the handshake timeout. Since GSKit granularity is 1 second,
536 we round up the required value. */
537 timeout = Curl_timeleft(data, NULL, TRUE);
539 cc = CURLE_OPERATION_TIMEDOUT;
541 cc = set_numeric(data, connssl->handle, GSK_HANDSHAKE_TIMEOUT,
542 (timeout + 999) / 1000);
545 cc = set_numeric(data, connssl->handle, GSK_FD, conn->sock[sockindex]);
547 cc = set_ciphers(data, connssl->handle);
549 cc = set_enum(data, connssl->handle, GSK_PROTOCOL_SSLV2,
550 sslv2enable? GSK_PROTOCOL_SSLV2_ON:
551 GSK_PROTOCOL_SSLV2_OFF);
553 cc = set_enum(data, connssl->handle, GSK_PROTOCOL_SSLV3,
554 sslv3enable? GSK_PROTOCOL_SSLV3_ON:
555 GSK_PROTOCOL_SSLV3_OFF);
557 cc = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV1,
558 sslv3enable? GSK_PROTOCOL_TLSV1_ON:
559 GSK_PROTOCOL_TLSV1_OFF);
561 cc = set_enum(data, connssl->handle, GSK_SERVER_AUTH_TYPE,
562 data->set.ssl.verifypeer? GSK_SERVER_AUTH_FULL:
563 GSK_SERVER_AUTH_PASSTHRU);
566 /* Start handshake. Try asynchronous first. */
567 memset(&commarea, 0, sizeof commarea);
568 connssl->iocport = QsoCreateIOCompletionPort();
569 if(connssl->iocport != -1) {
570 cc = gskit_status(data, gsk_secure_soc_startInit(connssl->handle,
571 connssl->iocport, &commarea),
572 "gsk_secure_soc_startInit()", CURLE_SSL_CONNECT_ERROR);
574 connssl->connecting_state = ssl_connect_2;
578 close_async_handshake(connssl);
580 else if(errno != ENOBUFS)
581 cc = gskit_status(data, GSK_ERROR_IO, "QsoCreateIOCompletionPort()", 0);
583 /* No more completion port available. Use synchronous IO. */
584 cc = gskit_status(data, gsk_secure_soc_init(connssl->handle),
585 "gsk_secure_soc_init()", CURLE_SSL_CONNECT_ERROR);
587 connssl->connecting_state = ssl_connect_3;
593 /* Error: rollback. */
594 close_one(connssl, data);
599 static CURLcode gskit_connect_step2(struct connectdata * conn, int sockindex,
602 struct SessionHandle * data = conn->data;
603 struct ssl_connect_data * connssl = &conn->ssl[sockindex];
604 Qso_OverlappedIO_t cstat;
609 /* Poll or wait for end of SSL asynchronous handshake. */
612 timeout_ms = nonblocking? 0: Curl_timeleft(data, NULL, TRUE);
615 stmv.tv_sec = timeout_ms / 1000;
616 stmv.tv_usec = (timeout_ms - stmv.tv_sec * 1000) * 1000;
617 switch (QsoWaitForIOCompletion(connssl->iocport, &cstat, &stmv)) {
618 case 1: /* Operation complete. */
620 case -1: /* An error occurred: handshake still in progress. */
624 continue; /* Retry. */
627 failf(data, "QsoWaitForIOCompletion() I/O error: %s", strerror(errno));
628 cancel_async_handshake(conn, sockindex);
629 close_async_handshake(connssl);
630 return CURLE_SSL_CONNECT_ERROR;
633 case 0: /* Handshake in progress, timeout occurred. */
636 cancel_async_handshake(conn, sockindex);
637 close_async_handshake(connssl);
638 return CURLE_OPERATION_TIMEDOUT;
642 cc = gskit_status(data, cstat.returnValue, "SSL handshake",
643 CURLE_SSL_CONNECT_ERROR);
645 connssl->connecting_state = ssl_connect_3;
646 close_async_handshake(connssl);
651 static CURLcode gskit_connect_step3(struct connectdata * conn, int sockindex)
653 struct SessionHandle * data = conn->data;
654 struct ssl_connect_data * connssl = &conn->ssl[sockindex];
655 const gsk_cert_data_elem * cdev;
657 const gsk_cert_data_elem * p;
658 const char * cert = (const char *) NULL;
659 const char * certend;
663 /* SSL handshake done: gather certificate info and verify host. */
665 if(gskit_status(data, gsk_attribute_get_cert_info(connssl->handle,
666 GSK_PARTNER_CERT_INFO,
668 "gsk_attribute_get_cert_info()", CURLE_SSL_CONNECT_ERROR) ==
670 infof(data, "Server certificate:\n");
672 for(i = 0; i++ < cdec; p++)
673 switch (p->cert_data_id) {
675 cert = p->cert_data_p;
676 certend = cert + cdev->cert_data_l;
678 case CERT_DN_PRINTABLE:
679 infof(data, "\t subject: %.*s\n", p->cert_data_l, p->cert_data_p);
681 case CERT_ISSUER_DN_PRINTABLE:
682 infof(data, "\t issuer: %.*s\n", p->cert_data_l, p->cert_data_p);
684 case CERT_VALID_FROM:
685 infof(data, "\t start date: %.*s\n", p->cert_data_l, p->cert_data_p);
688 infof(data, "\t expire date: %.*s\n", p->cert_data_l, p->cert_data_p);
694 cc = Curl_verifyhost(conn, cert, certend);
698 /* The only place GSKit can get the whole CA chain is a validation
699 callback where no user data pointer is available. Therefore it's not
700 possible to copy this chain into our structures for CAINFO.
701 However the server certificate may be available, thus we can return
703 if(data->set.ssl.certinfo) {
704 if(Curl_ssl_init_certinfo(data, 1))
705 return CURLE_OUT_OF_MEMORY;
707 cc = Curl_extract_certinfo(conn, 0, cert, certend);
713 connssl->connecting_state = ssl_connect_done;
718 static CURLcode gskit_connect_common(struct connectdata * conn, int sockindex,
719 bool nonblocking, bool * done)
721 struct SessionHandle * data = conn->data;
722 struct ssl_connect_data * connssl = &conn->ssl[sockindex];
724 Qso_OverlappedIO_t cstat;
725 CURLcode cc = CURLE_OK;
727 *done = connssl->state == ssl_connection_complete;
731 /* Step 1: create session, start handshake. */
732 if(connssl->connecting_state == ssl_connect_1) {
733 /* check allowed time left */
734 timeout_ms = Curl_timeleft(data, NULL, TRUE);
737 /* no need to continue if time already is up */
738 failf(data, "SSL connection timeout");
739 cc = CURLE_OPERATION_TIMEDOUT;
742 cc = gskit_connect_step1(conn, sockindex);
745 /* Step 2: check if handshake is over. */
746 if(cc == CURLE_OK && connssl->connecting_state == ssl_connect_2) {
747 /* check allowed time left */
748 timeout_ms = Curl_timeleft(data, NULL, TRUE);
751 /* no need to continue if time already is up */
752 failf(data, "SSL connection timeout");
753 cc = CURLE_OPERATION_TIMEDOUT;
756 cc = gskit_connect_step2(conn, sockindex, nonblocking);
759 /* Step 3: gather certificate info, verify host. */
760 if(cc == CURLE_OK && connssl->connecting_state == ssl_connect_3)
761 cc = gskit_connect_step3(conn, sockindex);
764 close_one(connssl, data);
765 else if(connssl->connecting_state == ssl_connect_done) {
766 connssl->state = ssl_connection_complete;
767 connssl->connecting_state = ssl_connect_1;
768 conn->recv[sockindex] = gskit_recv;
769 conn->send[sockindex] = gskit_send;
777 CURLcode Curl_gskit_connect_nonblocking(struct connectdata * conn,
783 cc = gskit_connect_common(conn, sockindex, TRUE, done);
784 if(*done || cc != CURLE_OK)
785 conn->ssl[sockindex].connecting_state = ssl_connect_1;
790 CURLcode Curl_gskit_connect(struct connectdata * conn, int sockindex)
795 conn->ssl[sockindex].connecting_state = ssl_connect_1;
796 retcode = gskit_connect_common(conn, sockindex, FALSE, &done);
806 void Curl_gskit_close(struct connectdata * conn, int sockindex)
808 struct SessionHandle * data = conn->data;
809 struct ssl_connect_data * connssl = &conn->ssl[sockindex];
812 close_one(connssl, data);
816 int Curl_gskit_close_all(struct SessionHandle * data)
824 int Curl_gskit_shutdown(struct connectdata * conn, int sockindex)
826 struct ssl_connect_data * connssl = &conn->ssl[sockindex];
827 struct SessionHandle * data = conn->data;
836 if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
839 close_one(connssl, data);
841 what = Curl_socket_ready(conn->sock[sockindex],
842 CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
846 /* anything that gets here is fatally bad */
847 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
852 if(!what) { /* timeout */
853 failf(data, "SSL shutdown timeout");
857 /* Something to read, let's do it and hope that it is the close
858 notify alert from the server. No way to gsk_secure_soc_read() now, so
861 nread = read(conn->sock[sockindex], buf, sizeof(buf));
864 failf(data, "read: %s", strerror(errno));
871 what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0);
878 size_t Curl_gskit_version(char * buffer, size_t size)
880 strncpy(buffer, "GSKit", size);
881 return strlen(buffer);
885 int Curl_gskit_check_cxn(struct connectdata * cxn)
890 /* The only thing that can be tested here is at the socket level. */
892 if(!cxn->ssl[FIRSTSOCKET].handle)
893 return 0; /* connection has been closed */
898 if(getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR,
899 (unsigned char *) &err, &errlen) ||
900 errlen != sizeof err || err)
901 return 0; /* connection has been closed */
903 return -1; /* connection status unknown */
906 #endif /* USE_GSKIT */