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;
211 rc = SSL_Handshake(h, SSL_HANDSHAKE_AS_CLIENT);
215 case 0: /* No error. */
218 case SSL_ERROR_BAD_CERTIFICATE:
219 case SSL_ERROR_BAD_CERT_SIG:
220 case SSL_ERROR_NOT_TRUSTED_ROOT:
221 return CURLE_PEER_FAILED_VERIFICATION;
223 case SSL_ERROR_BAD_CIPHER_SUITE:
224 case SSL_ERROR_NO_CIPHERS:
225 return CURLE_SSL_CIPHER;
227 case SSL_ERROR_CERTIFICATE_REJECTED:
228 case SSL_ERROR_CERT_EXPIRED:
229 case SSL_ERROR_NO_CERTIFICATE:
230 return CURLE_SSL_CERTPROBLEM;
233 failf(data, "SSL_Handshake() I/O error: %s", strerror(errno));
234 return CURLE_SSL_CONNECT_ERROR;
237 failf(data, "SSL_Handshake(): %s", SSL_Strerror(rc, NULL));
238 return CURLE_SSL_CONNECT_ERROR;
242 rc = Curl_verifyhost(conn, h->peerCert, h->peerCert + h->peerCertLen);
246 /* Gather certificate info. */
247 if(data->set.ssl.certinfo) {
248 if(Curl_ssl_init_certinfo(data, 1))
249 return CURLE_OUT_OF_MEMORY;
251 rc = Curl_extract_certinfo(conn, 0, h->peerCert,
252 h->peerCert + h->peerCertLen);
262 static Curl_recv qsossl_recv;
263 static Curl_send qsossl_send;
265 CURLcode Curl_qsossl_connect(struct connectdata * conn, int sockindex)
268 struct SessionHandle * data = conn->data;
269 struct ssl_connect_data * connssl = &conn->ssl[sockindex];
272 rc = Curl_qsossl_init_session(data);
275 rc = Curl_qsossl_create(conn, sockindex);
278 rc = Curl_qsossl_handshake(conn, sockindex);
280 SSL_Destroy(connssl->handle);
285 conn->recv[sockindex] = qsossl_recv;
286 conn->send[sockindex] = qsossl_send;
287 connssl->state = ssl_connection_complete;
290 connssl->handle = NULL;
291 connssl->use = FALSE;
292 connssl->state = ssl_connection_none;
299 static int Curl_qsossl_close_one(struct ssl_connect_data * conn,
300 struct SessionHandle * data)
308 rc = SSL_Destroy(conn->handle);
311 if(rc == SSL_ERROR_IO) {
312 failf(data, "SSL_Destroy() I/O error: %s", strerror(errno));
317 failf(data, "SSL_Destroy() returned error %s", SSL_Strerror(rc, NULL));
326 void Curl_qsossl_close(struct connectdata *conn, int sockindex)
329 struct SessionHandle *data = conn->data;
330 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
333 (void) Curl_qsossl_close_one(connssl, data);
337 int Curl_qsossl_close_all(struct SessionHandle * data)
346 int Curl_qsossl_shutdown(struct connectdata * conn, int sockindex)
349 struct ssl_connect_data * connssl = &conn->ssl[sockindex];
350 struct SessionHandle *data = conn->data;
359 if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
362 if(Curl_qsossl_close_one(connssl, data))
367 what = Curl_socket_ready(conn->sock[sockindex],
368 CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
372 /* anything that gets here is fatally bad */
373 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
378 if(!what) { /* timeout */
379 failf(data, "SSL shutdown timeout");
383 /* Something to read, let's do it and hope that it is the close
384 notify alert from the server. No way to SSL_Read now, so use read(). */
386 nread = read(conn->sock[sockindex], buf, sizeof(buf));
389 failf(data, "read: %s", strerror(errno));
396 what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0);
403 static ssize_t qsossl_send(struct connectdata * conn, int sockindex,
404 const void * mem, size_t len, CURLcode * curlcode)
407 /* SSL_Write() is said to return 'int' while write() and send() returns
411 rc = SSL_Write(conn->ssl[sockindex].handle, (void *) mem, (int) len);
416 case SSL_ERROR_BAD_STATE:
417 /* The operation did not complete; the same SSL I/O function
418 should be called again later. This is basically an EWOULDBLOCK
420 *curlcode = CURLE_AGAIN;
427 *curlcode = CURLE_AGAIN;
431 failf(conn->data, "SSL_Write() I/O error: %s", strerror(errno));
432 *curlcode = CURLE_SEND_ERROR;
437 failf(conn->data, "SSL_Write() returned error %s",
438 SSL_Strerror(rc, NULL));
439 *curlcode = CURLE_SEND_ERROR;
443 return (ssize_t) rc; /* number of bytes */
447 static ssize_t qsossl_recv(struct connectdata * conn, int num, char * buf,
448 size_t buffersize, CURLcode * curlcode)
451 char error_buffer[120]; /* OpenSSL documents that this must be at
452 least 120 bytes long. */
453 unsigned long sslerror;
457 buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
458 nread = SSL_Read(conn->ssl[num].handle, buf, buffsize);
461 /* failed SSL_read */
465 case SSL_ERROR_BAD_STATE:
466 /* there's data pending, re-invoke SSL_Read(). */
467 *curlcode = CURLE_AGAIN;
473 *curlcode = CURLE_AGAIN;
477 failf(conn->data, "SSL_Read() I/O error: %s", strerror(errno));
478 *curlcode = CURLE_RECV_ERROR;
482 failf(conn->data, "SSL read error: %s", SSL_Strerror(nread, NULL));
483 *curlcode = CURLE_RECV_ERROR;
487 return (ssize_t) nread;
491 size_t Curl_qsossl_version(char * buffer, size_t size)
494 strncpy(buffer, "IBM OS/400 SSL", size);
495 return strlen(buffer);
499 int Curl_qsossl_check_cxn(struct connectdata * cxn)
505 /* The only thing that can be tested here is at the socket level. */
507 if(!cxn->ssl[FIRSTSOCKET].handle)
508 return 0; /* connection has been closed */
513 if(getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR,
514 (unsigned char *) &err, &errlen) ||
515 errlen != sizeof err || err)
516 return 0; /* connection has been closed */
518 return -1; /* connection status unknown */
521 #endif /* USE_QSOSSL */