1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2010, 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 ***************************************************************************/
33 #include <curl/curl.h>
38 #include "connect.h" /* for the connect timeout */
40 #include "curl_memory.h"
41 /* The last #include file should be: */
45 int Curl_qsossl_init(void)
48 /* Nothing to do here. We must have connection data to initialize ssl, so
56 void Curl_qsossl_cleanup(void)
63 static CURLcode Curl_qsossl_init_session(struct SessionHandle * data)
69 SSLInitApp initappstr;
71 /* Initialize the job for SSL according to the current parameters.
72 * QsoSSL offers two ways to do it: SSL_Init_Application() that uses an
73 * application identifier to select certificates in the main certificate
74 * store, and SSL_Init() that uses named keyring files and a password.
75 * It is not possible to have different keyrings for the CAs and the
76 * local certificate. We thus use the certificate name to identify the
77 * keyring if given, else the CA file name.
78 * If the key file name is given, it is taken as the password for the
79 * keyring in certificate file.
80 * We first try to SSL_Init_Application(), then SSL_Init() if it failed.
83 certname = data->set.str[STRING_CERT];
86 certname = data->set.str[STRING_SSL_CAFILE];
89 return CURLE_OK; /* Use previous setup. */
92 memset((char *) &initappstr, 0, sizeof initappstr);
93 initappstr.applicationID = certname;
94 initappstr.applicationIDLen = strlen(certname);
95 initappstr.protocol = SSL_VERSION_CURRENT; /* TLSV1 compat. SSLV[23]. */
96 initappstr.sessionType = SSL_REGISTERED_AS_CLIENT;
97 rc = SSL_Init_Application(&initappstr);
99 if(rc == SSL_ERROR_NOT_REGISTERED) {
100 initstr.keyringFileName = certname;
101 initstr.keyringPassword = data->set.str[STRING_KEY];
102 initstr.cipherSuiteList = NULL; /* Use default. */
103 initstr.cipherSuiteListLen = 0;
104 rc = SSL_Init(&initstr);
109 case 0: /* No error. */
113 failf(data, "SSL_Init() I/O error: %s", strerror(errno));
114 return CURLE_SSL_CONNECT_ERROR;
116 case SSL_ERROR_BAD_CIPHER_SUITE:
117 return CURLE_SSL_CIPHER;
119 case SSL_ERROR_KEYPASSWORD_EXPIRED:
120 case SSL_ERROR_NOT_REGISTERED:
121 return CURLE_SSL_CONNECT_ERROR;
123 case SSL_ERROR_NO_KEYRING:
124 return CURLE_SSL_CACERT;
126 case SSL_ERROR_CERT_EXPIRED:
127 return CURLE_SSL_CERTPROBLEM;
130 failf(data, "SSL_Init(): %s", SSL_Strerror(rc, NULL));
131 return CURLE_SSL_CONNECT_ERROR;
138 static CURLcode Curl_qsossl_create(struct connectdata * conn, int sockindex)
142 struct ssl_connect_data * connssl = &conn->ssl[sockindex];
144 h = SSL_Create(conn->sock[sockindex], SSL_ENCRYPT);
147 failf(conn->data, "SSL_Create() I/O error: %s", strerror(errno));
148 return CURLE_SSL_CONNECT_ERROR;
156 static int Curl_qsossl_trap_cert(SSLHandle * h)
159 return 1; /* Accept certificate. */
163 static CURLcode Curl_qsossl_handshake(struct connectdata * conn, int sockindex)
167 struct SessionHandle * data = conn->data;
168 struct ssl_connect_data * connssl = &conn->ssl[sockindex];
169 SSLHandle * h = connssl->handle;
174 if(!data->set.ssl.verifyhost)
175 h->exitPgm = Curl_qsossl_trap_cert;
177 /* figure out how long time we should wait at maximum */
178 timeout_ms = Curl_timeleft(conn, NULL, TRUE);
181 /* time-out, bail out, go home */
182 failf(data, "Connection time-out");
183 return CURLE_OPERATION_TIMEDOUT;
186 /* SSL_Handshake() timeout resolution is second, so round up. */
187 h->timeout = (timeout_ms + 1000 - 1) / 1000;
189 /* Set-up protocol. */
191 switch (data->set.ssl.version) {
194 case CURL_SSLVERSION_DEFAULT:
195 h->protocol = SSL_VERSION_CURRENT; /* TLSV1 compat. SSLV[23]. */
198 case CURL_SSLVERSION_TLSv1:
199 h->protocol = TLS_VERSION_1;
202 case CURL_SSLVERSION_SSLv2:
203 h->protocol = SSL_VERSION_2;
206 case CURL_SSLVERSION_SSLv3:
207 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;
245 static Curl_recv qsossl_recv;
246 static Curl_send qsossl_send;
248 CURLcode Curl_qsossl_connect(struct connectdata * conn, int sockindex)
251 struct SessionHandle * data = conn->data;
252 struct ssl_connect_data * connssl = &conn->ssl[sockindex];
255 rc = Curl_qsossl_init_session(data);
258 rc = Curl_qsossl_create(conn, sockindex);
261 rc = Curl_qsossl_handshake(conn, sockindex);
263 SSL_Destroy(connssl->handle);
264 connssl->handle = NULL;
265 connssl->use = FALSE;
266 connssl->state = ssl_connection_none;
269 if (rc == CURLE_OK) {
270 connssl->state = ssl_connection_complete;
271 conn->recv[sockindex] = qsossl_recv;
272 conn->send[sockindex] = qsossl_send;
279 static int Curl_qsossl_close_one(struct ssl_connect_data * conn,
280 struct SessionHandle * data)
288 rc = SSL_Destroy(conn->handle);
291 if(rc == SSL_ERROR_IO) {
292 failf(data, "SSL_Destroy() I/O error: %s", strerror(errno));
297 failf(data, "SSL_Destroy() returned error %s", SSL_Strerror(rc, NULL));
306 void Curl_qsossl_close(struct connectdata *conn, int sockindex)
309 struct SessionHandle *data = conn->data;
310 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
313 (void) Curl_qsossl_close_one(connssl, data);
317 int Curl_qsossl_close_all(struct SessionHandle * data)
326 int Curl_qsossl_shutdown(struct connectdata * conn, int sockindex)
329 struct ssl_connect_data * connssl = &conn->ssl[sockindex];
330 struct SessionHandle *data = conn->data;
339 if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
342 if(Curl_qsossl_close_one(connssl, data))
347 what = Curl_socket_ready(conn->sock[sockindex],
348 CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
352 /* anything that gets here is fatally bad */
353 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
358 if(!what) { /* timeout */
359 failf(data, "SSL shutdown timeout");
363 /* Something to read, let's do it and hope that it is the close
364 notify alert from the server. No way to SSL_Read now, so use read(). */
366 nread = read(conn->sock[sockindex], buf, sizeof(buf));
369 failf(data, "read: %s", strerror(errno));
376 what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0);
383 static ssize_t qsossl_send(struct connectdata * conn, int sockindex,
384 const void * mem, size_t len, CURLcode * curlcode)
387 /* SSL_Write() is said to return 'int' while write() and send() returns
391 rc = SSL_Write(conn->ssl[sockindex].handle, (void *) mem, (int) len);
396 case SSL_ERROR_BAD_STATE:
397 /* The operation did not complete; the same SSL I/O function
398 should be called again later. This is basicly an EWOULDBLOCK
400 *curlcode = CURLE_AGAIN;
407 *curlcode = CURLE_AGAIN;
411 failf(conn->data, "SSL_Write() I/O error: %s", strerror(errno));
412 *curlcode = CURLE_SEND_ERROR;
417 failf(conn->data, "SSL_Write() returned error %s",
418 SSL_Strerror(rc, NULL));
419 *curlcode = CURLE_SEND_ERROR;
423 return (ssize_t) rc; /* number of bytes */
427 static ssize_t qsossl_recv(struct connectdata * conn, int num, char * buf,
428 size_t buffersize, CURLcode * curlcode)
431 char error_buffer[120]; /* OpenSSL documents that this must be at
432 least 120 bytes long. */
433 unsigned long sslerror;
437 buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
438 nread = SSL_Read(conn->ssl[num].handle, buf, buffsize);
441 /* failed SSL_read */
445 case SSL_ERROR_BAD_STATE:
446 /* there's data pending, re-invoke SSL_Read(). */
447 *curlcode = CURLE_AGAIN;
453 *curlcode = CURLE_AGAIN;
457 failf(conn->data, "SSL_Read() I/O error: %s", strerror(errno));
458 *curlcode = CURLE_RECV_ERROR;
462 failf(conn->data, "SSL read error: %s", SSL_Strerror(nread, NULL));
463 *curlcode = CURLE_RECV_ERROR;
467 return (ssize_t) nread;
471 size_t Curl_qsossl_version(char * buffer, size_t size)
474 strncpy(buffer, "IBM OS/400 SSL", size);
475 return strlen(buffer);
479 int Curl_qsossl_check_cxn(struct connectdata * cxn)
485 /* The only thing that can be tested here is at the socket level. */
487 if(!cxn->ssl[FIRSTSOCKET].handle)
488 return 0; /* connection has been closed */
493 if(getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR,
494 (unsigned char *) &err, &errlen) ||
495 errlen != sizeof err || err)
496 return 0; /* connection has been closed */
498 return -1; /* connection status unknown */
501 #endif /* USE_QSOSSL */