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"
33 #include <curl/curl.h>
38 #include "connect.h" /* for the connect timeout */
41 #include "curl_memory.h"
42 /* The last #include file should be: */
46 int Curl_qsossl_init(void)
49 /* Nothing to do here. We must have connection data to initialize ssl, so
57 void Curl_qsossl_cleanup(void)
64 static CURLcode Curl_qsossl_init_session(struct SessionHandle * data)
70 SSLInitApp initappstr;
72 /* Initialize the job for SSL according to the current parameters.
73 * QsoSSL offers two ways to do it: SSL_Init_Application() that uses an
74 * application identifier to select certificates in the main certificate
75 * store, and SSL_Init() that uses named keyring files and a password.
76 * It is not possible to have different keyrings for the CAs and the
77 * local certificate. We thus use the certificate name to identify the
78 * keyring if given, else the CA file name.
79 * If the key file name is given, it is taken as the password for the
80 * keyring in certificate file.
81 * We first try to SSL_Init_Application(), then SSL_Init() if it failed.
84 certname = data->set.str[STRING_CERT];
87 certname = data->set.str[STRING_SSL_CAFILE];
90 return CURLE_OK; /* Use previous setup. */
93 memset((char *) &initappstr, 0, sizeof initappstr);
94 initappstr.applicationID = certname;
95 initappstr.applicationIDLen = strlen(certname);
96 initappstr.protocol = SSL_VERSION_CURRENT; /* TLSV1 compat. SSLV[23]. */
97 initappstr.sessionType = SSL_REGISTERED_AS_CLIENT;
98 rc = SSL_Init_Application(&initappstr);
100 if(rc == SSL_ERROR_NOT_REGISTERED) {
101 initstr.keyringFileName = certname;
102 initstr.keyringPassword = data->set.str[STRING_KEY];
103 initstr.cipherSuiteList = NULL; /* Use default. */
104 initstr.cipherSuiteListLen = 0;
105 rc = SSL_Init(&initstr);
110 case 0: /* No error. */
114 failf(data, "SSL_Init() I/O error: %s", strerror(errno));
115 return CURLE_SSL_CONNECT_ERROR;
117 case SSL_ERROR_BAD_CIPHER_SUITE:
118 return CURLE_SSL_CIPHER;
120 case SSL_ERROR_KEYPASSWORD_EXPIRED:
121 case SSL_ERROR_NOT_REGISTERED:
122 return CURLE_SSL_CONNECT_ERROR;
124 case SSL_ERROR_NO_KEYRING:
125 return CURLE_SSL_CACERT;
127 case SSL_ERROR_CERT_EXPIRED:
128 return CURLE_SSL_CERTPROBLEM;
131 failf(data, "SSL_Init(): %s", SSL_Strerror(rc, NULL));
132 return CURLE_SSL_CONNECT_ERROR;
139 static CURLcode Curl_qsossl_create(struct connectdata * conn, int sockindex)
143 struct ssl_connect_data * connssl = &conn->ssl[sockindex];
145 h = SSL_Create(conn->sock[sockindex], SSL_ENCRYPT);
148 failf(conn->data, "SSL_Create() I/O error: %s", strerror(errno));
149 return CURLE_SSL_CONNECT_ERROR;
157 static int Curl_qsossl_trap_cert(SSLHandle * h)
160 return 1; /* Accept certificate. */
164 static CURLcode Curl_qsossl_handshake(struct connectdata * conn, int sockindex)
168 struct SessionHandle * data = conn->data;
169 struct ssl_connect_data * connssl = &conn->ssl[sockindex];
170 SSLHandle * h = connssl->handle;
173 h->exitPgm = data->set.ssl.verifypeer? NULL: Curl_qsossl_trap_cert;
175 /* figure out how long time we should wait at maximum */
176 timeout_ms = Curl_timeleft(data, NULL, TRUE);
179 /* time-out, bail out, go home */
180 failf(data, "Connection time-out");
181 return CURLE_OPERATION_TIMEDOUT;
184 /* SSL_Handshake() timeout resolution is second, so round up. */
185 h->timeout = (timeout_ms + 1000 - 1) / 1000;
187 /* Set-up protocol. */
189 switch (data->set.ssl.version) {
192 case CURL_SSLVERSION_DEFAULT:
193 h->protocol = SSL_VERSION_CURRENT; /* TLSV1 compat. SSLV[23]. */
196 case CURL_SSLVERSION_TLSv1:
197 h->protocol = TLS_VERSION_1;
200 case CURL_SSLVERSION_SSLv2:
201 h->protocol = SSL_VERSION_2;
204 case CURL_SSLVERSION_SSLv3:
205 h->protocol = SSL_VERSION_3;
208 case CURL_SSLVERSION_TLSv1_0:
209 case CURL_SSLVERSION_TLSv1_1:
210 case CURL_SSLVERSION_TLSv1_2:
211 failf(data, "TLS minor version cannot be set");
212 return CURLE_SSL_CONNECT_ERROR;
217 rc = SSL_Handshake(h, SSL_HANDSHAKE_AS_CLIENT);
221 case 0: /* No error. */
224 case SSL_ERROR_BAD_CERTIFICATE:
225 case SSL_ERROR_BAD_CERT_SIG:
226 case SSL_ERROR_NOT_TRUSTED_ROOT:
227 return CURLE_PEER_FAILED_VERIFICATION;
229 case SSL_ERROR_BAD_CIPHER_SUITE:
230 case SSL_ERROR_NO_CIPHERS:
231 return CURLE_SSL_CIPHER;
233 case SSL_ERROR_CERTIFICATE_REJECTED:
234 case SSL_ERROR_CERT_EXPIRED:
235 case SSL_ERROR_NO_CERTIFICATE:
236 return CURLE_SSL_CERTPROBLEM;
239 failf(data, "SSL_Handshake() I/O error: %s", strerror(errno));
240 return CURLE_SSL_CONNECT_ERROR;
243 failf(data, "SSL_Handshake(): %s", SSL_Strerror(rc, NULL));
244 return CURLE_SSL_CONNECT_ERROR;
248 rc = Curl_verifyhost(conn, h->peerCert, h->peerCert + h->peerCertLen);
252 /* Gather certificate info. */
253 if(data->set.ssl.certinfo) {
254 if(Curl_ssl_init_certinfo(data, 1))
255 return CURLE_OUT_OF_MEMORY;
257 rc = Curl_extract_certinfo(conn, 0, h->peerCert,
258 h->peerCert + h->peerCertLen);
268 static Curl_recv qsossl_recv;
269 static Curl_send qsossl_send;
271 CURLcode Curl_qsossl_connect(struct connectdata * conn, int sockindex)
274 struct SessionHandle * data = conn->data;
275 struct ssl_connect_data * connssl = &conn->ssl[sockindex];
278 rc = Curl_qsossl_init_session(data);
281 rc = Curl_qsossl_create(conn, sockindex);
284 rc = Curl_qsossl_handshake(conn, sockindex);
286 SSL_Destroy(connssl->handle);
291 conn->recv[sockindex] = qsossl_recv;
292 conn->send[sockindex] = qsossl_send;
293 connssl->state = ssl_connection_complete;
296 connssl->handle = NULL;
297 connssl->use = FALSE;
298 connssl->state = ssl_connection_none;
305 static int Curl_qsossl_close_one(struct ssl_connect_data * conn,
306 struct SessionHandle * data)
314 rc = SSL_Destroy(conn->handle);
317 if(rc == SSL_ERROR_IO) {
318 failf(data, "SSL_Destroy() I/O error: %s", strerror(errno));
323 failf(data, "SSL_Destroy() returned error %s", SSL_Strerror(rc, NULL));
332 void Curl_qsossl_close(struct connectdata *conn, int sockindex)
335 struct SessionHandle *data = conn->data;
336 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
339 (void) Curl_qsossl_close_one(connssl, data);
343 int Curl_qsossl_close_all(struct SessionHandle * data)
352 int Curl_qsossl_shutdown(struct connectdata * conn, int sockindex)
355 struct ssl_connect_data * connssl = &conn->ssl[sockindex];
356 struct SessionHandle *data = conn->data;
365 if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
368 if(Curl_qsossl_close_one(connssl, data))
373 what = Curl_socket_ready(conn->sock[sockindex],
374 CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
378 /* anything that gets here is fatally bad */
379 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
384 if(!what) { /* timeout */
385 failf(data, "SSL shutdown timeout");
389 /* Something to read, let's do it and hope that it is the close
390 notify alert from the server. No way to SSL_Read now, so use read(). */
392 nread = read(conn->sock[sockindex], buf, sizeof(buf));
395 failf(data, "read: %s", strerror(errno));
402 what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0);
409 static ssize_t qsossl_send(struct connectdata * conn, int sockindex,
410 const void * mem, size_t len, CURLcode * curlcode)
413 /* SSL_Write() is said to return 'int' while write() and send() returns
417 rc = SSL_Write(conn->ssl[sockindex].handle, (void *) mem, (int) len);
422 case SSL_ERROR_BAD_STATE:
423 /* The operation did not complete; the same SSL I/O function
424 should be called again later. This is basically an EWOULDBLOCK
426 *curlcode = CURLE_AGAIN;
433 *curlcode = CURLE_AGAIN;
437 failf(conn->data, "SSL_Write() I/O error: %s", strerror(errno));
438 *curlcode = CURLE_SEND_ERROR;
443 failf(conn->data, "SSL_Write() returned error %s",
444 SSL_Strerror(rc, NULL));
445 *curlcode = CURLE_SEND_ERROR;
449 return (ssize_t) rc; /* number of bytes */
453 static ssize_t qsossl_recv(struct connectdata * conn, int num, char * buf,
454 size_t buffersize, CURLcode * curlcode)
457 char error_buffer[120]; /* OpenSSL documents that this must be at
458 least 120 bytes long. */
459 unsigned long sslerror;
463 buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
464 nread = SSL_Read(conn->ssl[num].handle, buf, buffsize);
467 /* failed SSL_read */
471 case SSL_ERROR_BAD_STATE:
472 /* there's data pending, re-invoke SSL_Read(). */
473 *curlcode = CURLE_AGAIN;
479 *curlcode = CURLE_AGAIN;
483 failf(conn->data, "SSL_Read() I/O error: %s", strerror(errno));
484 *curlcode = CURLE_RECV_ERROR;
488 failf(conn->data, "SSL read error: %s", SSL_Strerror(nread, NULL));
489 *curlcode = CURLE_RECV_ERROR;
493 return (ssize_t) nread;
497 size_t Curl_qsossl_version(char * buffer, size_t size)
500 strncpy(buffer, "IBM OS/400 SSL", size);
501 return strlen(buffer);
505 int Curl_qsossl_check_cxn(struct connectdata * cxn)
511 /* The only thing that can be tested here is at the socket level. */
513 if(!cxn->ssl[FIRSTSOCKET].handle)
514 return 0; /* connection has been closed */
519 if(getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR,
520 (unsigned char *) &err, &errlen) ||
521 errlen != sizeof err || err)
522 return 0; /* connection has been closed */
524 return -1; /* connection status unknown */
527 #endif /* USE_QSOSSL */