1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
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.
13 *
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.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 * $Id: qssl.c,v 1.13 2008-05-20 10:21:50 patrickm Exp $
22 ***************************************************************************/
23
24 #include "setup.h"
25
26 #ifdef USE_QSOSSL
27 #include <qsossl.h>
28 #include <errno.h>
29 #include <string.h>
30
31 #include <curl/curl.h>
32 #include "urldata.h"
33 #include "sendf.h"
34 #include "qssl.h"
35 #include "sslgen.h"
36 #include "connect.h" /* for the connect timeout */
37 #include "select.h"
38 #include "memory.h"
39 /* The last #include file should be: */
40 #include "memdebug.h"
41
42
Curl_qsossl_init(void)43 int Curl_qsossl_init(void)
44
45 {
46 /* Nothing to do here. We must have connection data to initialize ssl, so
47 * defer.
48 */
49
50 return 1;
51 }
52
53
Curl_qsossl_cleanup(void)54 void Curl_qsossl_cleanup(void)
55
56 {
57 /* Nothing to do. */
58 }
59
60
Curl_qsossl_init_session(struct SessionHandle * data)61 static CURLcode Curl_qsossl_init_session(struct SessionHandle * data)
62
63 {
64 int rc;
65 char * certname;
66 SSLInit initstr;
67 SSLInitApp initappstr;
68
69 /* Initialize the job for SSL according to the current parameters.
70 * QsoSSL offers two ways to do it: SSL_Init_Application() that uses an
71 * application identifier to select certificates in the main certificate
72 * store, and SSL_Init() that uses named keyring files and a password.
73 * It is not possible to have different keyrings for the CAs and the
74 * local certificate. We thus use the certificate name to identify the
75 * keyring if given, else the CA file name.
76 * If the key file name is given, it is taken as the password for the
77 * keyring in certificate file.
78 * We first try to SSL_Init_Application(), then SSL_Init() if it failed.
79 */
80
81 certname = data->set.str[STRING_CERT];
82
83 if(!certname) {
84 certname = data->set.str[STRING_SSL_CAFILE];
85
86 if(!certname)
87 return CURLE_OK; /* Use previous setup. */
88 }
89
90 memset((char *) &initappstr, 0, sizeof initappstr);
91 initappstr.applicationID = certname;
92 initappstr.applicationIDLen = strlen(certname);
93 initappstr.protocol = SSL_VERSION_CURRENT; /* TLSV1 compat. SSLV[23]. */
94 initappstr.sessionType = SSL_REGISTERED_AS_CLIENT;
95 rc = SSL_Init_Application(&initappstr);
96
97 if(rc == SSL_ERROR_NOT_REGISTERED) {
98 initstr.keyringFileName = certname;
99 initstr.keyringPassword = data->set.str[STRING_KEY];
100 initstr.cipherSuiteList = NULL; /* Use default. */
101 initstr.cipherSuiteListLen = 0;
102 rc = SSL_Init(&initstr);
103 }
104
105 switch (rc) {
106
107 case 0: /* No error. */
108 break;
109
110 case SSL_ERROR_IO:
111 failf(data, "SSL_Init() I/O error: %s", strerror(errno));
112 return CURLE_SSL_CONNECT_ERROR;
113
114 case SSL_ERROR_BAD_CIPHER_SUITE:
115 return CURLE_SSL_CIPHER;
116
117 case SSL_ERROR_KEYPASSWORD_EXPIRED:
118 case SSL_ERROR_NOT_REGISTERED:
119 return CURLE_SSL_CONNECT_ERROR;
120
121 case SSL_ERROR_NO_KEYRING:
122 return CURLE_SSL_CACERT;
123
124 case SSL_ERROR_CERT_EXPIRED:
125 return CURLE_SSL_CERTPROBLEM;
126
127 default:
128 failf(data, "SSL_Init(): %s", SSL_Strerror(rc, NULL));
129 return CURLE_SSL_CONNECT_ERROR;
130 }
131
132 return CURLE_OK;
133 }
134
135
Curl_qsossl_create(struct connectdata * conn,int sockindex)136 static CURLcode Curl_qsossl_create(struct connectdata * conn, int sockindex)
137
138 {
139 SSLHandle * h;
140 struct ssl_connect_data * connssl = &conn->ssl[sockindex];
141
142 h = SSL_Create(conn->sock[sockindex], SSL_ENCRYPT);
143
144 if(!h) {
145 failf(conn->data, "SSL_Create() I/O error: %s", strerror(errno));
146 return CURLE_SSL_CONNECT_ERROR;
147 }
148
149 connssl->handle = h;
150 return CURLE_OK;
151 }
152
153
Curl_qsossl_trap_cert(SSLHandle * h)154 static int Curl_qsossl_trap_cert(SSLHandle * h)
155
156 {
157 return 1; /* Accept certificate. */
158 }
159
160
Curl_qsossl_handshake(struct connectdata * conn,int sockindex)161 static CURLcode Curl_qsossl_handshake(struct connectdata * conn, int sockindex)
162
163 {
164 int rc;
165 struct SessionHandle * data = conn->data;
166 struct ssl_connect_data * connssl = &conn->ssl[sockindex];
167 SSLHandle * h = connssl->handle;
168 long timeout_ms;
169
170 h->exitPgm = NULL;
171
172 if(!data->set.ssl.verifyhost)
173 h->exitPgm = Curl_qsossl_trap_cert;
174
175 /* figure out how long time we should wait at maximum */
176 timeout_ms = Curl_timeleft(conn, NULL, TRUE);
177
178 if(timeout_ms < 0) {
179 /* time-out, bail out, go home */
180 failf(data, "Connection time-out");
181 return CURLE_OPERATION_TIMEDOUT;
182 }
183
184 /* SSL_Handshake() timeout resolution is second, so round up. */
185 h->timeout = (timeout_ms + 1000 - 1) / 1000;
186
187 /* Set-up protocol. */
188
189 switch (data->set.ssl.version) {
190
191 default:
192 case CURL_SSLVERSION_DEFAULT:
193 h->protocol = SSL_VERSION_CURRENT; /* TLSV1 compat. SSLV[23]. */
194 break;
195
196 case CURL_SSLVERSION_TLSv1:
197 h->protocol = TLS_VERSION_1;
198 break;
199
200 case CURL_SSLVERSION_SSLv2:
201 h->protocol = SSL_VERSION_2;
202 break;
203
204 case CURL_SSLVERSION_SSLv3:
205 h->protocol = SSL_VERSION_3;
206 break;
207 }
208
209 rc = SSL_Handshake(h, SSL_HANDSHAKE_AS_CLIENT);
210
211 switch (rc) {
212
213 case 0: /* No error. */
214 break;
215
216 case SSL_ERROR_BAD_CERTIFICATE:
217 case SSL_ERROR_BAD_CERT_SIG:
218 case SSL_ERROR_NOT_TRUSTED_ROOT:
219 return CURLE_PEER_FAILED_VERIFICATION;
220
221 case SSL_ERROR_BAD_CIPHER_SUITE:
222 case SSL_ERROR_NO_CIPHERS:
223 return CURLE_SSL_CIPHER;
224
225 case SSL_ERROR_CERTIFICATE_REJECTED:
226 case SSL_ERROR_CERT_EXPIRED:
227 case SSL_ERROR_NO_CERTIFICATE:
228 return CURLE_SSL_CERTPROBLEM;
229
230 case SSL_ERROR_IO:
231 failf(data, "SSL_Handshake() I/O error: %s", strerror(errno));
232 return CURLE_SSL_CONNECT_ERROR;
233
234 default:
235 failf(data, "SSL_Handshake(): %s", SSL_Strerror(rc, NULL));
236 return CURLE_SSL_CONNECT_ERROR;
237 }
238
239 return CURLE_OK;
240 }
241
242
Curl_qsossl_connect(struct connectdata * conn,int sockindex)243 CURLcode Curl_qsossl_connect(struct connectdata * conn, int sockindex)
244
245 {
246 struct SessionHandle * data = conn->data;
247 struct ssl_connect_data * connssl = &conn->ssl[sockindex];
248 int rc;
249
250 rc = Curl_qsossl_init_session(data);
251
252 if(rc == CURLE_OK) {
253 rc = Curl_qsossl_create(conn, sockindex);
254
255 if(rc == CURLE_OK)
256 rc = Curl_qsossl_handshake(conn, sockindex);
257 else {
258 SSL_Destroy(connssl->handle);
259 connssl->handle = NULL;
260 connssl->use = FALSE;
261 connssl->state = ssl_connection_none;
262 }
263 }
264 if (rc == CURLE_OK)
265 connssl->state = ssl_connection_complete;
266
267 return rc;
268 }
269
270
Curl_qsossl_close_one(struct ssl_connect_data * conn,struct SessionHandle * data)271 static int Curl_qsossl_close_one(struct ssl_connect_data * conn,
272 struct SessionHandle * data)
273
274 {
275 int rc;
276
277 if(!conn->handle)
278 return 0;
279
280 rc = SSL_Destroy(conn->handle);
281
282 if(rc) {
283 if(rc == SSL_ERROR_IO) {
284 failf(data, "SSL_Destroy() I/O error: %s", strerror(errno));
285 return -1;
286 }
287
288 /* An SSL error. */
289 failf(data, "SSL_Destroy() returned error %d", SSL_Strerror(rc, NULL));
290 return -1;
291 }
292
293 conn->handle = NULL;
294 return 0;
295 }
296
297
Curl_qsossl_close(struct connectdata * conn,int sockindex)298 void Curl_qsossl_close(struct connectdata *conn, int sockindex)
299
300 {
301 struct SessionHandle *data = conn->data;
302 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
303
304 if(connssl->use)
305 (void) Curl_qsossl_close_one(connssl, data);
306 }
307
308
Curl_qsossl_close_all(struct SessionHandle * data)309 int Curl_qsossl_close_all(struct SessionHandle * data)
310
311 {
312 /* Unimplemented. */
313 (void) data;
314 return 0;
315 }
316
317
Curl_qsossl_shutdown(struct connectdata * conn,int sockindex)318 int Curl_qsossl_shutdown(struct connectdata * conn, int sockindex)
319
320 {
321 struct ssl_connect_data * connssl = &conn->ssl[sockindex];
322 struct SessionHandle *data = conn->data;
323 ssize_t nread;
324 int what;
325 int rc;
326 char buf[120];
327
328 if(!connssl->handle)
329 return 0;
330
331 if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
332 return 0;
333
334 if(Curl_qsossl_close_one(connssl, data))
335 return -1;
336
337 rc = 0;
338
339 what = Curl_socket_ready(conn->sock[sockindex],
340 CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
341
342 for (;;) {
343 if(what < 0) {
344 /* anything that gets here is fatally bad */
345 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
346 rc = -1;
347 break;
348 }
349
350 if(!what) { /* timeout */
351 failf(data, "SSL shutdown timeout");
352 break;
353 }
354
355 /* Something to read, let's do it and hope that it is the close
356 notify alert from the server. No way to SSL_Read now, so use read(). */
357
358 nread = read(conn->sock[sockindex], buf, sizeof(buf));
359
360 if(nread < 0) {
361 failf(data, "read: %s", strerror(errno));
362 rc = -1;
363 }
364
365 if(nread <= 0)
366 break;
367
368 what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0);
369 }
370
371 return rc;
372 }
373
374
Curl_qsossl_send(struct connectdata * conn,int sockindex,const void * mem,size_t len)375 ssize_t Curl_qsossl_send(struct connectdata * conn, int sockindex,
376 const void * mem, size_t len)
377
378 {
379 /* SSL_Write() is said to return 'int' while write() and send() returns
380 'size_t' */
381 int rc;
382
383 rc = SSL_Write(conn->ssl[sockindex].handle, (void *) mem, (int) len);
384
385 if(rc < 0) {
386 switch(rc) {
387
388 case SSL_ERROR_BAD_STATE:
389 /* The operation did not complete; the same SSL I/O function
390 should be called again later. This is basicly an EWOULDBLOCK
391 equivalent. */
392 return 0;
393
394 case SSL_ERROR_IO:
395 switch (errno) {
396 case EWOULDBLOCK:
397 case EINTR:
398 return 0;
399 }
400
401 failf(conn->data, "SSL_Write() I/O error: %s", strerror(errno));
402 return -1;
403 }
404
405 /* An SSL error. */
406 failf(conn->data, "SSL_Write() returned error %d",
407 SSL_Strerror(rc, NULL));
408 return -1;
409 }
410
411 return (ssize_t) rc; /* number of bytes */
412 }
413
414
Curl_qsossl_recv(struct connectdata * conn,int num,char * buf,size_t buffersize,bool * wouldblock)415 ssize_t Curl_qsossl_recv(struct connectdata * conn, int num, char * buf,
416 size_t buffersize, bool * wouldblock)
417
418 {
419 char error_buffer[120]; /* OpenSSL documents that this must be at
420 least 120 bytes long. */
421 unsigned long sslerror;
422 int nread;
423
424 nread = SSL_Read(conn->ssl[num].handle, buf, (int) buffersize);
425 *wouldblock = FALSE;
426
427 if(nread < 0) {
428 /* failed SSL_read */
429
430 switch (nread) {
431
432 case SSL_ERROR_BAD_STATE:
433 /* there's data pending, re-invoke SSL_Read(). */
434 *wouldblock = TRUE;
435 return -1; /* basically EWOULDBLOCK */
436
437 case SSL_ERROR_IO:
438 switch (errno) {
439 case EWOULDBLOCK:
440 *wouldblock = TRUE;
441 return -1;
442 }
443
444 failf(conn->data, "SSL_Read() I/O error: %s", strerror(errno));
445 return -1;
446
447 default:
448 failf(conn->data, "SSL read error: %s", SSL_Strerror(nread, NULL));
449 return -1;
450 }
451 }
452 return (ssize_t) nread;
453 }
454
455
Curl_qsossl_version(char * buffer,size_t size)456 size_t Curl_qsossl_version(char * buffer, size_t size)
457
458 {
459 strncpy(buffer, "IBM OS/400 SSL", size);
460 return strlen(buffer);
461 }
462
463
Curl_qsossl_check_cxn(struct connectdata * cxn)464 int Curl_qsossl_check_cxn(struct connectdata * cxn)
465
466 {
467 int err;
468 int errlen;
469
470 /* The only thing that can be tested here is at the socket level. */
471
472 if(!cxn->ssl[FIRSTSOCKET].handle)
473 return 0; /* connection has been closed */
474
475 err = 0;
476 errlen = sizeof err;
477
478 if(getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR,
479 (unsigned char *) &err, &errlen) ||
480 errlen != sizeof err || err)
481 return 0; /* connection has been closed */
482
483 return -1; /* connection status unknown */
484 }
485
486 #endif /* USE_QSOSSL */
487