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 */